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!

Keinen Artikel mehr verpassen

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