Home > front end >  HttpClient configured in Program.cs is not being passed to MediatR RequestHandler by dependency inje
HttpClient configured in Program.cs is not being passed to MediatR RequestHandler by dependency inje

Time:08-09

I'm working on a Blazor WebAssembly application in .NET 6.0.

I'm using MediatR requests and handlers.

public class DummyRequest : IRequest<string>
{
    public Guid Test { get; } = new Guid("e9f41a5d-5da6-4aad-b118-83476b7f40f4");
}


public class DummyHandler : IRequestHandler<DummyRequest, string>
{
    private readonly HttpClient _httpClient;

    public DummyHandler(HttpClient httpClient)
    {
        _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
    }

    public async Task<string> Handle(DummyRequest request, CancellationToken cancellationToken)
    {
      // This should be the value configured in Program.cs
        string baseAddress = _httpClient.BaseAddress?.AbsoluteUri ?? string.Empty;
        // But it's always blank, so we can't make any calls with the HttpClient

        await Task.CompletedTask;
        return "foobar";
    }
}

I'm configuring a different HttpClient for each request handler in Program.cs, then I'm adding MediatR:

builder.Services.AddHttpClient<DummyHandler>((client) => { client.BaseAddress = new Uri("https://api.somewhere.com"); });
builder.Services.AddMediatR(Assembly.GetExecutingAssembly());

I have also tried reversing those calls, so that I add MediatR first, and register the HttpClient for the DummyHandler type afterwards.

At runtime, after that Handler has been instantiated, it should have an _httpClient with a BaseAddress property set to "https://api.somewhere.com".

However, it always gets an HttpClient with a null BaseUri, so the Handler can't use the HttpClient in any operations.

Can anybody see what's gone wrong please?

CodePudding user response:

It seems that MediatR registers interface-implemetation pair so you need to follow the same pattern for the typed client registration. Try the following:

services.AddHttpClient<IRequestHandler<DummyRequest, string>, DummyHandler>((client) => { client.BaseAddress = new Uri("https://api.somewhere.com"); });

Gist with full test code.

CodePudding user response:

Instead of a typed httpclient, you could use a named httpclient.

Thus register as

builder.Services.AddHttpClient("somename", client => { client.BaseAddress = new Uri("https://api.somewhere.com"); });

And in the constructor, inject the httpclientfactory instead:

    public DummyHandler(HttpClientFactory httpClientFactory)
    {
        _httpClient = httpClientFactory.CreateClient("somename");
    }

CodePudding user response:

I suggest you to create the wrapper class around your Http client and register it instead.It hides implementation of your connection type and can be extended by other logic or other realization if you need.

Example:

class ApiConnection : IConnection
{
  private readonly HttpClient _client;

  public ApiConnection(...)
{
  _client = new HttpClient();
}
// some other logic

}

Add this class to your Handler (IConnection connection) and use it in handler.

Register as: services.AddSingleton<IConnection, APIConnection>();
  • Related