Extending HttpClient With Delegating Handlers in ASP.NET Core

Introduction

The HttpClient class is a powerful tool in the arsenal of developers building applications that communicate with external APIs or web services. In ASP.NET Core, the HttpClient is commonly used for making HTTP requests. One of the key features of HttpClient is its extensibility, and this can be achieved through the use of Delegating Handlers.

Delegating Handlers allow you to intercept and modify HTTP requests and responses in a pipeline before or after they are received. This mechanism provides a flexible and reusable way to add cross-cutting concerns to your HTTP requests, such as authentication, logging, error handling, or custom headers.

Understanding Delegating Handlers

In this context of HttpClient, a Delegating Handler is a class that inherits from DelegatingHandler and overrides the SendAsync method. This method is where the HTTP request is processed. By chaining multiple Delegating Handlers together, you can create a behaviour pipeline that each request will go through.

Creating a Custom Delegating Handler

Let's create a simple Delegating Handler that logs information about each HTTP request and response. First, create a new class that inherits from DelegatingHandler.

public class LoggingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Log information about the request
        Console.WriteLine($"Request: {request.Method} {request.RequestUri}");

        // Process the request in the base handler
        var response = await base.SendAsync(request, cancellationToken);

        // Log information about the response
        Console.WriteLine($"Response: {response.StatusCode}");

        return response;
    }
}

Registering the Custom Delegating Handler

To use the custom Delegating Handler, you need to register it in the Startup.cs file. Open the ConfigureServices method and add the following code.

public void ConfigureServices(IServiceCollection services)
{
    // Other service registrations

    // Register the custom Delegating Handler
    services.AddTransient<LoggingHandler>();
    
    // Register HttpClient with the custom Delegating Handler
    services.AddHttpClient("MyApiClient")
            .AddHttpMessageHandler<LoggingHandler>();
}

Here, we register the LoggingHandler as a transient service and then add it to the HttpClient pipeline using AddHttpMessageHandler. You can register multiple Delegating Handlers and control the order in which they are executed.

Using the Extended HttpClient

Now that you've extended HttpClient with a custom Delegating Handler, you can use it in your services or controllers.

public class MyService
{
    private readonly IHttpClientFactory _httpClientFactory;

    public MyService(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public async Task<string> GetDataFromApi()
    {
        var httpClient = _httpClientFactory.CreateClient("MyApiClient");

        // Make HTTP requests as usual
        var response = await httpClient.GetStringAsync("https://api.example.com/data");

        return response;
    }
}

Conclusion

In ASP.NET Core, extending HttpClient with Delegating Handlers offers a clean and modular way to add cross-cutting concerns to your HTTP requests. Whether it's logging, authentication, or custom header manipulation, Delegating Handlers provide a powerful mechanism for enhancing the functionality of HttpClient in a reusable and maintainable manner. By composing a pipeline of Delegating Handlers, developers can customize the behaviour HttpClient to meet the specific needs of their applications.