Skizzenhafte Darstellung von Serverblöcken, die mit Pfeilen und Cloud-Elementen verbunden sind

HTTPClients in ASP.NET Core – DelegatingHandlers vs. PrimaryMessageHandlers

Sven Hennessen

In modernen ASP.NET-Anwendungen – insbesondere mit der Einführung von Minimal APIs in .NET 9 – ist die Konfiguration von HTTPClients für externe Aufrufe sowohl leistungsstark als auch flexibel. Eine der wichtigsten Stärken ist die Möglichkeit, benannte HTTPClients zu erstellen und deren Verhalten durch Message-Handler zu erweitern. In diesem Beitrag untersuchen wir zwei Arten von Message-Handlern:

  • PrimaryMessageHandlers: Ermöglichen die Kontrolle über den zugrunde liegenden Transport (z. B. Aktivierung von TLS1.3, Anpassung der SSL-Zertifikatsvalidierung).
  • DelegatingHandlers: Erlauben das Modifizieren oder Überprüfen von HTTP-Anfragen und -Antworten auf Anwendungsebene (z. B. Festlegen der HTTP-Version, Logging, benutzerdefinierte Header).

Nachfolgend zeigen wir, wie jede dieser Methoden in Minimal API ASP.NET-Diensten eingesetzt werden kann, begleitet von Codebeispielen.


Benannte HTTPClients in Minimal API-Diensten

Die Abhängigkeitsinjektion von ASP.NET macht es einfach, benannte HTTPClients zu registrieren. Verschiedene Clients können mit unterschiedlichen Konfigurationen versehen und später über IHttpClientFactory abgerufen werden.

Beispiel für die Registrierung:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient("MyClient");
// Weitere benannte Clients hinzufügen

var app = builder.Build();

app.MapGet("/", async (IHttpClientFactory clientFactory) =>
{
    var client = clientFactory.CreateClient("MyClient");
    var response = await client.GetAsync("https://example.com");
    return await response.Content.ReadAsStringAsync();
});

app.Run();

PrimaryMessageHandlers: Anpassungen auf Transportebene

Der PrimaryMessageHandler ist der zugrunde liegende Handler, der sich um den Netzwerktransport kümmert. Durch seine Konfiguration können Details wie TLS-Protokolle und die Validierung von SSL-Zertifikaten angepasst werden. Dies ist besonders nützlich, wenn bestimmte Sicherheitsanforderungen durchgesetzt werden müssen.

Beispiel: Konfiguration von TLS1.3 und benutzerdefinierter SSL-Zertifikatsvalidierung

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient("MyPrimaryClient")
    .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
    {
        SslOptions = new SslClientAuthenticationOptions
        {
            // Erzwinge TLS1.3 für sichere Kommunikation
            EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls13,
            RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
            {
                // Benutzerdefinierte Logik zur Validierung von SSL-Zertifikaten
                Console.WriteLine("Primary handler: Validierung des SSL-Zertifikats.");
                return true; // Oder eine richtige Validierungslogik implementieren
            }
        }
    });
// Weitere benannte Clients konfigurieren

var app = builder.Build();

app.MapGet("/primary", async (IHttpClientFactory clientFactory) =>
{
    var client = clientFactory.CreateClient("MyPrimaryClient");
    var response = await client.GetAsync("https://example.com");
    return await response.Content.ReadAsStringAsync();
});

app.Run();

DelegatingHandlers: Anpassungen auf Anwendungsebene

DelegatingHandlers befinden sich in der HTTPClient-Pipeline und ermöglichen das Modifizieren von Anfragen oder Antworten. Sie eignen sich ideal für Aufgaben wie Logging, das Hinzufügen benutzerdefinierter Header oder das Erzwingen bestimmter Protokolle wie HTTP/2.

Beispiel: Benutzerdefinierter DelegatingHandler zur Erzwingung von HTTP/2

public class CustomDelegatingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Erzwinge HTTP/2 für ausgehende Anfragen
        request.Version = HttpVersion.Version20;
        Console.WriteLine("CustomDelegatingHandler: Anfrage wurde auf HTTP/2 gesetzt.");
        return await base.SendAsync(request, cancellationToken);
    }
}

Lektion gelernt

Der Versuch, die schlanke modulare Struktur von DelegatingHandlers zu nutzen, um Transportebenen-Konfigurationen anzuwenden, funktioniert nicht. Das Modifizieren des InnerHandler eines DelegatingHandler führt zu einer Ausnahme:

System.InvalidOperationException: Die ‘InnerHandler’-Eigenschaft muss null sein. ‘DelegatingHandler’-Instanzen, die ‘HttpMessageHandlerBuilder’ übergeben werden, dürfen nicht wiederverwendet oder zwischengespeichert werden.

Dies liegt daran, dass das Modifizieren des InnerHandler die Handler-Pipeline unterbrechen würde. Ein Umgehen der Ausnahme durch das Umhüllen jeder Anfrage mit einem neuen HttpMessageInvoker würde zwar funktionieren, aber den Verarbeitungsfluss unterbrechen.

Fazit: Verwende DelegatingHandlers nicht für Transportebenen-Anpassungen.

Registrierung des Handlers mit einem benannten HTTPClient

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient<CustomDelegatingHandler>();

builder.Services.AddHttpClient("MyDelegatingClient")
    .AddHttpMessageHandler<CustomDelegatingHandler>();

var app = builder.Build();

app.MapGet("/delegating", async (IHttpClientFactory clientFactory) =>
{
    var client = clientFactory.CreateClient("MyDelegatingClient");
    var response = await client.GetAsync("https://example.com");
    return await response.Content.ReadAsStringAsync();
});

app.Run();

Fazit

Durch die Kombination von DelegatingHandlers und PrimaryMessageHandlers kannst du die HTTP-Kommunikation in deinen ASP.NET Core Minimal API-Diensten präzise steuern:

  • Benannte HTTP-Clients bieten eine modulare Möglichkeit zur Konfiguration von HTTP-Clients für verschiedene Ziele.
  • PrimaryMessageHandlers ermöglichen Anpassungen auf Transportebene (z. B. Erzwingen von TLS1.3, Verwaltung der SSL-Zertifikatsvalidierung).
  • DelegatingHandlers erlauben Anpassungen auf Anwendungsebene (z. B. Erzwingen von HTTP/2, Hinzufügen von Headern).

Dieser mehrschichtige Ansatz ermöglicht robuste, sichere und flexible HTTP-Interaktionen, die speziell auf die Anforderungen deiner Anwendung zugeschnitten sind. Happy Coding!

Unterstützung benötigt?

Ihr wollt HTTP-Clients in euren ASP.NET Core Anwendungen optimal konfigurieren und sicher gestalten, aber seid unsicher bei der Umsetzung? Wir helfen euch gerne dabei! Meldet euch einfach über unsere Kontaktseite und wir schauen gemeinsam, wie wir eure API-Integration professionalisieren können.

Keinen Artikel mehr verpassen

Kein Spam. Nur relevante News über und von uns. Jederzeit abbestellbar.