Unleashing the Power of DelegateHandlers in ASP.NET Core
In the world of ASP.NET Core, HttpClient
is your go-to tool for making HTTP requests. But what if you need to intercept and modify these requests or responses? That's where DelegateHandler
comes into play. Think of it as a middleware pipeline specifically for your HttpClient
requests.
What is a DelegateHandler?
A DelegateHandler
is an abstract class that allows you to create custom handlers for processing HTTP requests and responses. It acts as a link in the chain of handlers that an HttpClient
uses. By creating your own DelegateHandler
, you can add custom logic to manipulate requests before they are sent and responses before they are received.
Why use DelegateHandlers?
- Authentication: Add authentication headers to every request.
- Logging: Log request and response details for debugging.
- Caching: Implement custom caching logic.
- Retry Logic: Automatically retry failed requests.
- Request/Response Transformation: Modify request or response content.
- Authorization: Implement custom authorization checks.
- Adding custom headers: Add common headers to all outgoing requests.
Creating a Custom DelegateHandler
To create a custom DelegateHandler
, you need to inherit from the DelegatingHandler
class and override the SendAsync
method. This method takes an HttpRequestMessage
and a CancellationToken
as input and returns a Task<HttpResponseMessage>
.
Here’s a basic example of a LoggingHandler
that logs the request URL and response status code:
using System.Diagnostics;
public class LoggingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
Debug.WriteLine($"Request: {request.RequestUri}");
var response = await base.SendAsync(request, cancellationToken);
Debug.WriteLine($"Response: {response.StatusCode}");
return response;
}
}
Using the DelegateHandler
To use your custom DelegateHandler
, you need to register it with the HttpClient
during its configuration. This is typically done in the ConfigureServices
method of your Startup.cs
(or Program.cs
in .NET 6+).
Here’s how you can register the LoggingHandler
using IHttpClientFactory
:
using Microsoft.Extensions.DependencyInjection;
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("MyClient")
.AddHttpMessageHandler<LoggingHandler>();
}
Now, whenever you create an HttpClient
using the "MyClient" named client, the LoggingHandler
will be part of the request pipeline.
Complete Example with Authentication Handler:
Here’s a more advanced example that demonstrates how to create an authentication handler that adds an authorization header to every request:
using System.Net.Http.Headers;
public class AuthenticationHandler : DelegatingHandler
{
private readonly string _apiKey;
public AuthenticationHandler(string apiKey)
{
_apiKey = apiKey;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _apiKey);
return await base.SendAsync(request, cancellationToken);
}
}
And here’s how you would register it in ConfigureServices
:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("AuthenticatedClient")
.AddHttpMessageHandler(() => new AuthenticationHandler("your_api_key"));
}
Consuming the HttpClient:
Finally, you can consume the HttpClient
using IHttpClientFactory
in your controllers or services:
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
public class MyController : ControllerBase
{
private readonly IHttpClientFactory _clientFactory;
public MyController(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
[HttpGet("data")]
public async Task<IActionResult> GetData()
{
var client = _clientFactory.CreateClient("AuthenticatedClient"); // or MyClient
var response = await client.GetAsync("https://example.com/data");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return Ok(content);
}
return BadRequest(response.StatusCode);
}
}
Chaining DelegateHandlers:
You can chain multiple DelegateHandler
instances together to create a complex request pipeline. The order in which you add them matters, as they will be executed in that order.
Key Takeaways:
DelegateHandler
provides a powerful mechanism for customizingHttpClient
requests and responses.- It allows you to implement cross-cutting concerns like authentication, logging, and caching.
IHttpClientFactory
simplifies the management and configuration ofHttpClient
instances.- Chaining handlers enables complex request processing pipelines.
By leveraging DelegateHandler
, you can create robust and maintainable HTTP clients in your ASP.NET Core applications.
Thank you for reading if you have any doubts. drop the message in comments.
Follow me on Medium or LinkedIn to read more about ASP.Net Core and Angular