问题
I've created a custom library which automatically sets up Polly policies for specific services which depend on HttpClient
.
This is done using the IServiceCollection
extension methods and the typed client approach. A simplified example:
public static IHttpClientBuilder SetUpFooServiceHttpClient(this IServiceCollection services)
{
return services
.AddHttpClient<FooService>()
.AddPolicyHandler(GetRetryPolicy());
}
The example service:
public class FooService
{
private readonly HttpClient _client;
// OPTION 1
public FooService(HttpClient httpClient)
{
_client = httpClient;
}
// OPTION 2
public FooService(IHttpClientFactory httpClientFactory)
{
_client = httpClientFactory.CreateClient(GetType().Name);
}
public void DoJob()
{
var test = _client.GetAsync("http://example.com");
}
}
Fetching the service from the DI container (this is from a test project):
var services = new ServiceCollection();
services.SetUpFooServiceHttpClient();
services.AddSingleton<FooService>();
var fooService = services
.BuildServiceProvider()
.GetRequiredService<FooService>();
// Perform test
fooService.DoJob();
Note: In this test project, I also add an extra mocked handler since I'm trying to mock http status responses, but the mocked handler being present or not is identical to the Polly policy being present or not, so I omitted the mocked handler from the example code.
Notice the two different constructors in FooService
. Depending on which one I comment out and which one I leave in, I get different outcomes. All other code remains untouched.
- Option 1, injecting the
HttpClient
directly, ignores all my configuration. I get a standard http client with no Polly policy handler. - Options 2, injecting the
IHttpClientFactory
and requesting the client using the current type name (i.e.FooService
) respect my configuration. I get a custom http client which contains the Polly policy handler (and any other handlers I may have configured, e.g. mocked handlers in my test suite)
The absence/existence of the policy handler is confirmed in both cases using debug inspection.
According to all documentation I've found on the subject, both options should be equivalent, at least in regards to the constructed HttpClient
that I obtain in the end. But that is not the case here.
The documentation I find specifies that HttpClient
can be injected when using typed clients:
- The MSDN documentation, specifically the "typed clients" section example.
- This SO answer
- This blog post
I'm using a typed client but injecting a HttpClient
clearly doesn't work for me.
Why does injecting a HttpClient
vs injecting IHttpClientFactory
work differently in my case?
回答1:
In effect, you have the following two registrations for your FooService
class:
services.AddHttpClient<FooService>()
services.AddSingleton<FooService>();
Because of how the DI container works behind-the-scenes, the second registration overwrites the first. If you remove the second registration, the first will be used, and so your constructor with the HttpClient
parameter will be invoked.
来源:https://stackoverflow.com/questions/63056470/injected-httpclient-ignores-ihttpclientfactory-configuration