Reputation: 1644
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?
Upvotes: 1
Views: 2067
Reputation: 198
In case you are using the IRequestHandler<SomeCommand>
alternative where there is no response, MediatR internally converts it to to IRequestHandler<SomeCommand, Unit>
, which is what you will need to use to properly inject the HTTP client in your DI:
serviceCollection
.AddHttpClient<IRequestHandler<SomeCommand, Unit>, SomeCommandHandler>((httpClient) =>
{
...
});
Upvotes: 0
Reputation: 11261
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");
}
Upvotes: 1
Reputation: 390
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>();
Upvotes: 0
Reputation: 141690
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.
Upvotes: 2