Should I cache and reuse HttpClient created from HttpClientFactory?
HttpClient
is only IDisposable
because its HttpMessageHandler
is IDisposable
. In reality, it's the HttpMessageHandler
which should be long-lived.
HttpClientFactory
works by keeping a long-lived HttpMessageHandler
internally. Whenever you ask for a HttpClient
, it uses the long-lived HttpMessageHander
, and tells the HttpClient
not to dispose it when the HttpClient
is disposed.
You can see that on GitHub:
public HttpClient CreateClient(string name)
{
// ...
// Get a cached HttpMessageHandler
var handler = CreateHandler(name);
// Give it to a new HttpClient, and tell it not to dispose it
var client = new HttpClient(handler, disposeHandler: false);
// ...
return client;
}
So, technically it doesn't matter whether you cache the HttpClient
or dispose it straight away - disposing it doesn't do anything (because it's been told not to dispose its HttpClientHandler
, as that's managed by the HttpClientFactory
).
Regarding disposing the HttpClient
, MSDN says:
Disposal of the client isn't required. Disposal cancels outgoing requests and guarantees the given HttpClient instance can't be used after calling Dispose. IHttpClientFactory tracks and disposes resources used by HttpClient instances. The HttpClient instances can generally be treated as .NET objects not requiring disposal.
Keeping a single HttpClient instance alive for a long duration is a common pattern used before the inception of IHttpClientFactory. This pattern becomes unnecessary after migrating to IHttpClientFactory.
I suspect the SocketException
s you're seeing have a different cause. Perhaps ask a new question focussed on them?
Things have changed in a good way in the ASP.NET Core 2.2
release.
The way the HttpClient
is expected to be consumed is through DI only, which internally handles all the necessary caching for you using HttpClientFactory
. The following documentation article has been updated to reflect on these new use cases: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2
Also, @RyanNowak from ASP.NET Core team has covered all these changes in the following ASP.Net Core Community Standup session: https://www.youtube.com/watch?v=Lb12ZtlyMPg If you haven't watched it, I strongly recommend watching it, as it's super informative and educating.
Here is a small sample to showcase the usage. In the Startup.ConfigureServices
method call:
services.AddHttpClient();
Note: There are multiple usage patterns, this is the most basic one. Look into the docs for other patterns, which may suite your needs better.
Later, in the class, where from you'd like to make http requests, take a dependency on IHttpClientFactory
and let DI instantiate it for you as necessary. Here is the sample from Microsoft Docs:
public class BasicUsageModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubBranch> Branches { get; private set; }
public bool GetBranchesError { get; private set; }
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/aspnet/docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
Branches = await response.Content
.ReadAsAsync<IEnumerable<GitHubBranch>>();
}
else
{
GetBranchesError = true;
Branches = Array.Empty<GitHubBranch>();
}
}
}