ASP.NET Core Web API - JWT Message Handler - No Registered Type Error

Viewed 577

I have created a JWT Token Handler for my Web API project. The idea is that this API is merely a gateway to other APIs and a token is shared across them all. So when a call is made to my API and I am forwarding the call to another, I want to automatically forward the JWT that was attached to the initial request.

I made a custom MessageHandler as seen below:

public class JwtTokenHeaderHandler : DelegatingHandler
{
    private readonly HttpContext httpContext;
   public JwtTokenHeaderHandler(HttpContext httpContext)
   {
       this.httpContext = httpContext;
   }
   protected override async Task<HttpResponseMessage> SendAsync(
       HttpRequestMessage request,
       CancellationToken cancellationToken)
   {
       string savedToken = await this.httpContext.GetTokenAsync("access_token");
       request.Headers.Add("bearer", savedToken);
       return await base.SendAsync(request, cancellationToken);
   } 
}

Then I registered it as a service in the Startup as below:

services.AddTransient<HttpMessageHandler>(p => p.GetRequiredService<JwtTokenHeaderHandler>());

IHttpClientBuilder serviceClientBuilder = services.AddHttpClient<IService, Service>(client =>
{
    client.BaseAddress = new Uri(this.Configuration.GetValue<string>("ServiceURL"));
}).AddHttpMessageHandler<JwtTokenHeaderHandler>();

The application runs up until a request is made and then this exception comes up:

An unhandled exception has occurred while executing the request.

System.InvalidOperationException: No service for type 'Application.API1.JwtTokenHeaderHandler' has been registered. at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.<>c__4`1.b__4_1(HttpMessageHandlerBuilder b) at Microsoft.Extensions.Http.DefaultHttpClientFactory.<>c__DisplayClass17_0.g__Configure|0(HttpMessageHandlerBuilder b) at Microsoft.Extensions.Http.LoggingHttpMessageHandlerBuilderFilter.<>c__DisplayClass3_0.b__0(HttpMessageHandlerBuilder builder)

1 Answers

First, injecting HttpContext directly will cause issues. Use IHttpContextAccessor and access the context in the Send method.

public class JwtTokenHeaderHandler : DelegatingHandler {
    private readonly IHttpContextAccessor accessor;

    public JwtTokenHeaderHandler(IHttpContextAccessor accessor) {
        this.accessor = accessor;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
        string savedToken = await accessor.HttpContext.GetTokenAsync("access_token");
        request.Headers.Add("bearer", savedToken);
        return await base.SendAsync(request, cancellationToken);
    } 
}

Next GetRequiredService throws that exception when the requested service is not registered with the collection so make sure to register the handler with the container

Note

The handler type must be registered as a transient service.

Reference AddHttpMessageHandler<THandler>(IHttpClientBuilder)

services.AddTransient<JwtTokenHeaderHandler>();

So that JwtTokenHeaderHandler can be resolved when requested from the service provider

services.AddTransient<HttpMessageHandler>(p => p.GetRequiredService<JwtTokenHeaderHandler>());
services.AddHttpClient<IService, Service>(client => {
    client.BaseAddress = new Uri(this.Configuration.GetValue<string>("ServiceURL"));
}).AddHttpMessageHandler<JwtTokenHeaderHandler>();
Related