In any real-time application, we call some kind of third-party service or REST API, and any REST API does some kind of request validation like checking token in the request header, etc.. and it's achieved using Filters or Middleware in ASP.NET Core API.
If we think of reverse i.e. validating all the outgoing requests from our application or simply logging the outgoing requests going out of our application then DelegatingHandler in ASP.Net Web API does the same job as middleware does for the incoming requests.
DelegatingHandler
Creating the Handler
public class MessageHandler : DelegatingHandler
{
private readonly ILogger<MessageHandler> _logger;
public MessageHandler(ILogger<MessageHandler> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
_logger.LogInformation($"Logging the Outgoing request", request);
// Call the inner handler.
var response = await base.SendAsync(request, cancellationToken);
_logger.LogInformation($"Logging the Outgoing response", request);
return response;
}
}
Suppose we want to validate all the outgoing requests whether they are having a header named "api-key" in their request then it can be achieved using the below code.
public class ValidateRequestHandler : DelegatingHandler
{
private readonly ILogger<ValidateRequestHandler> _logger;
public ValidateRequestHandler(ILogger<ValidateRequestHandler> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (!request.Headers.Contains("api-key"))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent("Please provide an API key header called api-key")
};
}
// Call the inner handler.
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
In the above handler, we can see it returns 400 Bad request if it doesn't find the header named "api-key" in the request.
Add Header to all the outgoing request
public class AddRequestHeaderHandler : DelegatingHandler
{
private readonly ILogger<AddRequestHeaderHandler> _logger;
public AddRequestHeaderHandler(ILogger<AddRequestHeaderHandler> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("api-key", GetAPIKey());
// Call the inner handler.
var response = await base.SendAsync(request, cancellationToken);
return response;
}
private string GetAPIKey()
{
// returning random string for example
return "jhfsfksnfhsfd;lslhfsdjfslfds";
}
}
The above method is used for adding a header to all the outgoing requests from the application.
Registering the Handler
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddTransient<ValidateRequestHandler>();
services.AddRefitClient<IStudentClient>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://localhost:44391"))
.AddHttpMessageHandler<ValidateRequestHandler>();
}
In the registration of handler, you can see I am using AddRefitHandler which is from Refit Nuget Library and you can check this article to get the knowledge regarding Refit.
Suppose we want to use both MessageHandler as well as ValidateRequestHandler for a particular third-party API then we use like below
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddTransient<ValidateRequestHandler>();
services.AddTransient<MessageHandler>();
services.AddRefitClient<IStudentClient>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://localhost:44391"))
.AddHttpMessageHandler<ValidateRequestHandler>()
.AddHttpMessageHandler<MessageHandler>();
}
Similarly, if we want to use a different handler for different third party APIs then we can use like below
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddTransient<ValidateRequestHandler>();
services.AddTransient<MessageHandler>();
services.AddTransient<AddRequestHeaderHandler>();
services.AddRefitClient<IStudentClient>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://localhost:44391"))
.AddHttpMessageHandler<ValidateRequestHandler>()
.AddHttpMessageHandler<MessageHandler>();
services.AddRefitClient<IFeesClient>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://localhost:4500"))
.AddHttpMessageHandler<AddRequestHeaderHandler>();
}
As you can see AddRequestHeaderHandler is only used for IFeesClient third party service and ValidateRequestHandler or MessageHandler is used for IStudentClient third party service.
Conclusion
As we saw DelegatingHandler can help us to perform multiple kinds of tasks for the outgoing request like adding a header, validating the header, logging the request, etc...
Please note if we are calling multiple third-party APIs from our application and we want to use our delegatinghandler for all the third-party APIs then we have to use AddHttpMessageHandler method for all the APIs in the ConfigureServices method.
Hope you understand DelegatingHandler in ASP.Net Core and DelegatingHandler can be used in the Legacy DotNet framework as well and only difference is that of registration.
Share This Post
Support Me