2

I am trying to setup named HttpClient in Blazor WASM. Problem is that I need to call async method in order to get JWT.

builder.Services.AddHttpClient("auth", async c =>
    {
        // access the DI container
        var serviceProvider = builder.Services.BuildServiceProvider();
        // Find the HttpContextAccessor service
        var localStorageService = serviceProvider.GetService<ILocalStorageService>();
        // Get the bearer token.
        if (localStorageService == null) return;
        
        var jwt = await localStorageService.GetJwtAsync();
        Console.WriteLine("JWT "+jwt);
        if (jwt != null)
        {
            c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
        }
    }
);

This doesn't work since parameter c cannot be async function.

Next I tried something like this

builder.Services.AddHttpClient("auth", c =>
    {
        // access the DI container
        var serviceProvider = builder.Services.BuildServiceProvider();
        // Find the HttpContextAccessor service
        var localStorageService = serviceProvider.GetService<ILocalStorageService>();
        // Get the bearer token.
        if (localStorageService == null) return;
        
        var jwt = localStorageService.GetJwtAsync().Result;
        Console.WriteLine("JWT "+jwt);
        if (jwt != null)
        {
            c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
        }
    }
);

In this case I get an error

Unhandled exception rendering component: Cannot wait on monitors on this runtime

because I am using .Result in WASM and it is blocking the main thread.

Any ideas is this possible to implement and how?

1 Answer 1

2

Consider writing a custom DelegatingHandler.

A DelegatingHandler is a decorator that can be used to add behavior before or after the inner Http Handler will be called by overriding the SendAsync method.

In your case the handler could look like in the example below:

public class LocalStorageAuthHandler : DelegatingHandler
{  
    private readonly ILocalStorageService _localStorageService;
  
    public LocalStorageAuthHandler(ILocalStorageService localStorageService)
    {
         _localStorageService = localStorageService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, 
        CancellationToken cancellationToken)
    {
        // Access local storage service and update headers accordingly
        return await base.SendAsync(request, cancellationToken);
    }
}

Then add the handler to your HttpClient:

// Transient, Scoped or Singleton depends on your code:
services.AddTransient<LocalStorageAuthHandler>();
services.AddHttpClient("clientName")
    .AddHttpMessageHandler<LocalStorageAuthHandler>();

This will use the LocalStorageAuthHandler with the default http message handler as inner handler.

You can even combine multiple DelegatingHandlers to build a Chain of Responsibility.

See Make HTTP requests using IHttpClientFactory in ASP.NET Core on Microsoft Learn for details.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, works great! You have one mistake though, it should be "return await base.SendAsync(request, cancellationToken);" instead of "return await SendAsync(request, cancellationToken);". It creates recursive function that never ends.
And constructor name should be "LocalStorageAuthHandler" instead of "CustomHandler". Leaving this in comment just in case someone else wants to use this with copy-paste style
Glad it helped :) Fixed the errors in my Answer.
I used this answer but needed to use it with HttpClientFactory for all HttpClient instances (for use with NSwag). I found that combining the above answer with the following answer : stackoverflow.com/questions/64103349/… Gave me exactly what I needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.