How to use "ICachedServiceProvider" to inject "Typed HttpClient" correctly?
I use Typed HttpClient
and try to use ICachedServiceProvider
, but I got an error.
var httpClient = _cachedServiceProvider.GetRequiredService<HttpClient>();
Error message:
System.InvalidOperationException An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set. at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request)
But it work fine when I use Constructor Injection
for Typed HttpClient
private readonly HttpClient _httpClient;
public TestService(HttpClient httpClient)
{
_httpClient = httpClient;
}
P.S. ConfigureServices
:
private void ConfigureHttpClient(ServiceConfigurationContext context)
{
var options = context.Services.ExecutePreConfiguredActions<TestOptions>();
context.Services.AddHttpClient<ITestService, TestService>(httpClient =>
{
httpClient.BaseAddress = options.BaseAddress;
});
}
So, how to use "ICachedServiceProvider" to inject "Typed HttpClient" correctly?
Edit:
I can use IHttpClientFactory
to get named HttpClient
, and it work now.
var httpClientFactory = _cachedServiceProvider.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient(nameof(ITestService));
// ...
var response = await httpClient.PostAsJsonAsync("oauth/token", testRequest);
First, an important clarification: in the question, TestService
is the typed client.
HttpClient
instances.
A typed client accepts an
HttpClient
parameter in its constructor[.]
HttpClient
instances.Next, a clarification about what the method calls do:
AddHttpClient<ITestService, TestService>(httpClient => {...})
configures a binding between the typed client TestService
and a named client.
_cachedServiceProvider.GetRequiredService<HttpClient>()
returns a scope-cached HttpClient
, not a typed client (neither ITestService
nor TestService
is passed) nor a named client (name is not passed). That's why it's not configured.
httpClientFactory.CreateClient(nameof(ITestService))
creates a named client, not the typed client (i.e. TestService
).
Then, by definition, a typed client constructor-injects a named client.
HttpService
is practically a lightweight wrapper around longer-lived HTTP connections. There should be no need to scope-cache it.
Simply:
var testService = _cachedServiceProvider.GetRequiredService<TestService>();
You should constructor-inject HttpClient
in TestService
.
If you use ICachedServiceProvider
to inject IHttpClientFactory
(Singleton), you will actually get Singleton IHttpClientFactory
. CachedServiceProvider
just caches the instance for the scope, it does not (nor should it) change the lifecycle of the registered type.