Der Lebenszyklus der HTTP-Anforderungslogik

In dieser Lerneinheit machen Sie sich mit dem Lebenszyklus der HTTP-Anforderungslogik in der ProductService-Klasse des Projekts ContosoPets.UI vertraut.

Vorteile einer typisierten HTTPClient-Dienstarchitektur

Wie in der vorherigen Lerneinheit erwähnt, ist die ProductService-Klasse ein Beispiel für eine typisierte HttpClient-Dienstarchitektur und für die Verarbeitung von HTTP-Anforderungen zuständig, die an die Web-API gesendet werden. Der Dienst wird als typisierter Dienst bereitgestellt. Daraus ergibt sich der Vorteil, dass er per Dependency Injection als Konstruktorparameter direkt den PageModel-Klassen in diesem Projekt übergeben werden kann. Ein Vorteil dieser Architektur besteht darin, dass das Framework dafür verantwortlich ist, eine Instanz der HttpClient-Klasse zu erstellen und diese freizugeben, wenn sie nicht mehr benötigt wird. Dieses Feature eignet sich sehr gut für Projekte wie das hier vorgestellte, in dem HttpClient-Instanzen für jeden CRUD-Vorgang verwendet werden.

Überblick über die Struktur der ProductService-Klassendatei, die Registrierung und die Instanziierung als typisierter Dienst

Öffnen Sie die ProductService.cs-Klassendatei, die sich im Verzeichnis ContosoPets.Ui/Services/ befindet. Der folgende Code sollte angezeigt werden:

using ContosoPets.Ui.Models;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;

namespace ContosoPets.Ui.Services
{
    public class ProductService
    {
        private readonly string _route;
        private readonly HttpClient _httpClient;

        public ProductService(
            HttpClient httpClient,
            IConfiguration configuration)
        {
            _httpClient = httpClient;
            _route = configuration["ProductService:ControllerRoute"];
        }

        public async Task<IEnumerable<Product>> GetProducts()
        {
            var response = await _httpClient.GetAsync(_route);
            response.EnsureSuccessStatusCode();

            var products = await response.Content.ReadAsAsync<IEnumerable<Product>>();

            return products;
        }

        public async Task<Product> GetProductById(int productId)
        {
            var response = await _httpClient.GetAsync($"{_route}/{productId}");
            response.EnsureSuccessStatusCode();

            var product = await response.Content.ReadAsAsync<Product>();

            return product;
        }

        public async Task UpdateProduct(Product product)
        {
            await _httpClient.PutAsJsonAsync<Product>($"{_route}/{product.Id}", product);
        }

        public async Task CreateProduct(Product product)
        {
            await _httpClient.PostAsJsonAsync<Product>(_route, product);
        }

        public async Task DeleteProduct(int productId)
        {
            await _httpClient.DeleteAsync($"{_route}/{productId}");
        }
    }
}

Im Folgenden erfahren Sie, wie ProductService beim Start als Dienst verfügbar gemacht wird.

Der Konstruktor der ProductService-Klasse nimmt im Codeausschnitt unten als Parameter eine Instanz von HttpClient (System.Net.Http.HttpClient) entgegen.

public ProductService(
    HttpClient httpClient,
    IConfiguration configuration)
{
    _httpClient = httpClient;
    _route = configuration["ProductService:ControllerRoute"];
}

Wenn ProductService beim Start in der Methode Startup.ConfigureServices, die sich inStartup.cs befindet, als Dienst registriert wird, wird die Klasse instanziiert und der App zur Verfügung gestellt. Dies sehen Sie im folgenden Codeausschnitt:

services.AddHttpClient<ProductService>(config => {
    config.BaseAddress = new Uri(Configuration["ProductService:BaseAddress"]);
    config.DefaultRequestHeaders.Add("Accept", "application/json");
});

Der BaseAddress-URI wird von der HttpClient-Instanz für alle Anforderungen verwendet, die an die Web-API gesendet werden. Dieser URI wird im folgenden ProductService-Konfigurationseintrag in der Datei appsettings.json festgelegt:

  "ProductService": {
    "BaseAddress": "http://localhost:55964",
    "ControllerRoute": "/api/products"
  },

Sie wissen nun, wie ProductService der Anwendung beim Start als Dienst zur Verfügung gestellt wird. Als Nächstes lernen Sie den Lebenszyklus der Methode CreateProduct kennen.

Der Lebenszyklus der Methode CreateProduct

  1. Der Benutzer übermittelt die Produktdaten über das Formular der Razor-Seite Create.cshtml, wobei eine POST-Anforderung verwendet wird.
  2. Das Eingabe-Taghilfsprogramm verwendet die [DataAnnotation]-Attribute, die im Product-Modell festgelegt sind, und erzeugt HTML-Attribute, die für die clientseitige jQuery-Validierung erforderlich sind. Das POST-Ereignis darf nur verarbeitet werden, wenn die Daten gültig sind. In vielen Fällen werden Validierungsfehler auf dem Client erkannt und nie an den Server gesendet.
  3. Die Methode OnPostAsync der Create-Klasse verarbeitet das POST-Ereignis serverseitig und überprüft ModelState auf Validierungsfehler. Dies sehen Sie im folgenden Codeausschnitt:
public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    await _productService.CreateProduct(Product);

    return RedirectToPage("Index");
}

Wenn ModelState in diesem Code ungültig ist, wird die Page-Hilfsmethode aufgerufen. Page gibt eine Instanz von PageResult zurück.

Wenn ModelState gültig ist, ruft die Methode OnPostAsync die Methode CreateProduct der ProductService-Klasse auf und übergibt eine Instanz des Product-Modells, wie im folgenden Codeausschnitt gezeigt wird:

await _productService.CreateProduct(Product);

return RedirectToPage("Index");
  1. Die HttpClient-Instanz sendet eine POST-Anforderung als asynchronen Vorgang mit dem festgelegten product-Wert an die angegebene URI-Zeichenfolge _route, wobei die Werte als JSON serialisiert werden.
public async Task CreateProduct(Product product)
{
    await _httpClient.PostAsJsonAsync<Product>(_route, product);
}

Wie bereits erwähnt, wird der ProductService-Dienst wird dem CreateModel direkt über einen Konstruktorparameter mithilfe von DI übergeben.

Wenn die ASP.NET Core-Runtime feststellt, dass die HTTPClient-Instanz nicht mehr verwendet wird, gibt die Runtime sie automatisch frei.

Sie verfügen nun über ein vollständiges Projekt, das die neue Razor-Seite Create und die zugehörige PageModel-Klasse umfasst. Außerdem haben Sie erfahren, wie die neue Razor-Seite Create und das zugehörige PageModel Dependency Injection nutzen und die Methoden der ProductService-Klasse im Projekt ContosoPets.UI aufrufen, die die HTTP-Anforderungslogik kapseln.

Als Nächstes erstellen Sie die aktualisierte ContosoPets.UI-Anwendung, stellen diese bereit und testen sie.