blazorblazor-webassembly

Using a named HttpClient in a service in Blazor WASM


I'm a bit confused about how to use a named HttpClient which is registered as scoped in a service that is registered as a singleton. I've seen similar questions but I'm still not very clear about the usage.

Here's my service that needs to use the named HttpClient to make API calls to my backend:

public class MyApiService : IMyApiService
{
   private readonly HttpClient _myApiHttpClient;

   public MyApiService(HttpClient myApiHttpClient)
   {
      _myApiHttpClient = myApiHttpClient;
   }

   public async Task<List<Customer>> GetCustomers()
   {
      var response = await _myApiHttpClient.GetAsync("/customers");
      if(!response.IsSuccessStatusCode)
         throw new Exception("API call failed!");

      var json = await response.Content.ReadAsStringAsync();
      return JsonSerializer.Deserialize<List<Customer>>(json);
   }
}

And in the Program.cs, I register them as follows:

...
// Add HttpClient for API calls
builder.Services.AddHttpClient("MyApi",
        client => client.BaseAddress = new Uri("https://api.test.com"))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
    .CreateClient("MyApi"));

// Register services
builder.Services.AddSingleton<IMyApiService, MyApiService>();

await builder.Build().RunAsync();

This approach is throwing the following error:

Cannot consume scoped service 'System.Net.Http.HttpClient' from singleton 'MyBlazorWasmApp.Services.IMyApiService'

I understand why I get the error message. I haven't yet been able to figure out how to use the HttpClient I define for calling my API in my singleton services.

P.S. A quick and dirty approach would be to define my services as scoped as in a Blazor WASM app, there would be no difference between registering them as singleton or scoped but I want to understand how to handle this scenario.


Solution

  • You can't, but you don't need to.

    Use the IHttpClientFactory to obtain short lived HttpClient instances in a similar fashion to IDbContextFactory. It's a much safer strategy in the async world of Blazor.

    Your service injects the IHttpClientFactory, and GetCustomers gets a HttpClient, scoped to the lifetime of GetCustomers, to make the API call.

    Read more here: https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory

    And note: https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#avoid-typed-clients-in-singleton-services