die Geschichte des HTTP Request in .NET

Sozusagen am Anfang stand der Web Client. Mit der gleichnamigen Klasse aus dem Namensraum System.Net sind einfache REST Requests für GET, POST, UPDATE und DELETE möglich. Dabei wird der Netzwerk Socket Layer mit einer Zugriffs Api versehen um ggf eine Socket Connection auf Port 80 oder 443 zu erstellen und mit den einfachen HTTP Codes zu verarbeiten.

Der Nachfolger HttpClient steht schon lange in den Startlöchern, trotzdem findet man noch immer Anhänger von WebClient.

Auch Blazor nutzt eine bzw sogar 2 modernerer Varianten von HttpClient. Erstellt sie ein neues Blazor WebAssembly Projekt als ASP.NET Core hosted

image

Visual Studio erstellt drei Projekt in der Projektmappe. Eines davon enthält einen Web Api Controller für Fake Wetterdaten. Im .Client Projekt enthält der Razor VIew der Blazor Webassembly App folgende Zeile Code

1: forecasts = await Http.GetJsonAsync<WeatherForecast[]>

("WeatherForecast");

Der Http Client wird per Dependency Injection als Referenz mit den Namen Http erstellt. Spannender ist die einzeilige Lösung von Download und Deserialisierung der Json Daten. Der String Parameter entspricht dem Web Api Controller. Da sich dieser im gleichen Verzeichnis befindet ohne die übliche Routing Url. Der Objekt Typ WeatherForeCast wird über das .Shared Projekt referenziert und als Array geliefert. MIt GetJsonAsync wird die Rest Wäsche gewaschen, getrocknet, gebügelt und in den Schrank gelegt.

Das nützliche Helferlein stammt aus der Extension Methode Microsoft.AspNetCore.Blazor.HttpClient. Die Dokumentation schreibt dazu, das man dies nur im Browser einsetzen soll. Also nicht in der Blazor Server Variante (nicht zu verwechseln mit Server Hosted).

Wie sieht nun die auscodierte Variante für den Web Server aus? Bei beiden Varianten (Server/Client) ist das HTTPClient Objekt im DI Container anzumelden. Blazor Client macht dies in programm.cs per  AddBaseAddressHttpClient. Blazor Server in Startup.cs per DI Service Collection und .AddScoped<HttpClient>.  Es reicht sodann die Referenz im der Razor View Page per @Inject.

   1:  var response= await Http.GetAsync(
@"https://localhost:5001/weatherforecast");
   2:  if (response.IsSuccessStatusCode)
   3:     {
   4:     using var responseStream = await 
response.Content.ReadAsStreamAsync();

5: forecasts= await JsonSerializer.DeserializeAsync

<WeatherForecast[]>(responseStream);

   6:     }

Im zusammenspiel mit ASP.NET Web Api werden die Feldnamen mit Kleinbuchstaben beginnend (CamelCase) im Json übermittelt. Mittels zweiten Parameter im Methodenaufruf Deserialize, kann das als Option mitgegeben werden.

   1:  var options = new JsonSerializerOptions
   2:   {
   3:     PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
   4:  };

In manchen Beispielen findet sich eine Methode ReadAsAsync um die Daten in ein .NET Objekt zu konvertieren. Wieder eine Extension Methode. Installieren sie das Paket Microsoft.AspNet.WebApi.Client um dann mit einer Zeile C# Code das Ziel zu erreichen

   1:  forecasts = await response.Content.
ReadAsAsync<WeatherForecast[]>();

Allerdings hängt das Paket von Newtonsoft Json Parser ab und nicht vom Neuen System:.Text.Json. Also nicht zukunftsfähig.

Nun ist HttClient nur eine Abstraktion einer System Api. Naturgemäß braucht .NET und sein Garbage Collector länger um Ressourcen wieder frei zugegen. Das kann bei einem Webserver der massiv Socket Verbindungen aufbaut um externe Rest Services zu nutzen, schnell zu Problemen führen.

Alles gut? mitnichten – erstens Corona und zweitens HttpClientFactory. Wer REST Calls vom Webserver ausführt kann schnell in diverse Nöte kommen. Bereits mit aspnet core 2.1 hat Microsoft sich dem Problem angenommen und sozusagen eine Abstraktion des HttpClients erstellt. Mit der HTTPClientfactory lassen sich verschiedene Probleme lösen. Logging und Retry über Polly. Wichtigste Funktion ist allerdings polling von offenen Http Verbindungen zu externen Web Servern.

Der einfachste Fall erfordert in der Startup.cs per Dependency Service die Extension Methode zum registrieren des Services.

   1:   services.AddHttpClient();

In der Blazor Komponente wird eine Referenz geholt.

   1:  @inject IHttpClientFactory Http

In der Server Blazor Page muss allerdings erst aus dem Factory Objekt ein Client Objekt angefordert werden mit CreateClient.

   1:  protected override async Task OnInitializedAsync()
   2:  {
   3:   var client = Http.CreateClient();
   4:   var response= await client.GetAsync(@"https://localhost:5001/WeatherForecast");
   5:   if (response.IsSuccessStatusCode)
   6:     {
   7:       var options = new JsonSerializerOptions
   8:        {
   9:        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
  10:        };
  11:        using var responseStream = 
await response.Content.ReadAsStreamAsync();
  12:        forecasts = await JsonSerializer.DeserializeAsync
<WeatherForecast[]>(responseStream,options);
Kommentare sind geschlossen