How to manage the HttpClient instance in a class library - c#

I'm writing a .Net Core class library that is a wrapper around a REST web service. I'm using HttpClient which should be instantiated as a singleton.
The big question I have now is how should I manage this HttpClient instance? Should it be the role of my class library, or of the calling code that would pass the instance to my class library.
I started with the first solution, creating a singleton instance this way:
public class DemoClient : IDemoClient
{
private static readonly HttpClient HttpClient;
static DemoClient()
{
HttpClient = new HttpClient();
}
public DemoClient(Uri baseUrl)
{
HttpClient.BaseAddress = baseUrl;
}
}
I use the static constructor to instantiate the singleton instance and set the baseUrl in the "standard" constructor.
There's a few things I don't like about this approach. First, if the user of my class library creates a second instance of the class, setting the baseUrl to something else, it will break completely, first because once a query has been made, setting the BaseAddress throws an exception and secondly because even if you could, it would not be possible for each instance to have a different BaseAddress.
This means that either I force the user to create a singleton of my class which means that he wouldn't be able to create two instances for two different REST endpoint or I forget about making the HttpClient instance singleton but this might end up being a bad idea with the risk of wasting sockets.
The second solution would mean I'd simply leave the instantiation of the HttpClient to the user of my library, and ask him to pass it to my constructor. It would definitely simplify the management (at least for me :)) but it feels like leaking implementation details.
I might in the future change and use a different approach than HttpClient and this shouldn't have any impact of the user of my library. Moreover, it asks the user of the library to actually know how to use the HttpClient (and how to use it correctly), which doesn't feel "right" as well.
Is there another option I haven't thought about? This issue of having the HttpClient instance a singleton is quite annoying...

Related

What is the lifetime of a typed HttpClient instance from IHttpClientFactory where the type that will receive it is registered as "AddScoped"?

TL;DR
In .NET 6:
What is the lifetime of a typed HttpClient instance from IHttpClientFactory where the type that will receive it is registered as "Scoped"?
Shouldn't it be kind of a "timed singleton" (regardless of the lifetime of the class that will use it) when we register it like the excerpt below? Or is the HttpClient Transient - and .NET doesn't cache any of its configurations and only the Handler is pooled?
services.AddHttpClient<IServiceInterface, ServiceImpl>(client =>
{
client.BaseAddress = "<some absolute URL here>";
}
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
services.AddScoped<IServiceInterface, ServiceImpl>();
Context
The application I'm working on accesses several external APIs at different addresses. I've encapsulated each service access logic into Service classes with their respective interfaces, so they could be injected at runtime. As prescribed by Microsoft, I'm using Typed HttpClients, and I wrote a helper method to configure them at the Startup.cs:
public static IServiceCollection ConfigureHttpClientForService<TInterface, TImpl>
(this IServiceCollection services, Func<IServiceProvider, Uri> func)
where TInterface : class
where TImpl : class, TInterface
{
services.AddHttpClient<TInterface, TImpl>((provider, client) =>
{
var uri = func(provider);
client.BaseAddress = uri;
})
// Polly Rules here and other stuff
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
return services;
}
Then, on Startup.cs ConfigureServices method I call it like this:
services
.ConfigureHttpClientForService<IServiceInterface, ServiceImpl>(provider =>
{
if (!Uri.TryCreate(
settings.UrlObjConfig.Url,
UriKind.RelativeOrAbsolute,
out var uri))
{
throw new UriFormatException("Invalid URL");
}
return uri;
});
At runtime, I've noticed that the Action<HttpClient> that configures the HttpClient (AddHttpClient<TClient,TImplementation>(IServiceCollection, Action<HttpClient>) - docs) is being called every single time when I call a method from a service that uses the typed client - in other words, every time a Scoped service gets instantiated, that Action is being run.
Questions
What is the lifetime of a typed HttpClient instance from IHttpClientFactory where the type that will receive it is registered as "AddScoped"?
Is this behaviour correct? Shouldn't the HttpClient configuration (e.g. Base Address) be cached somehow or saved somewhere, since it is typed?
Wouldn't it create some GC pressure (lots of clients being created for the same type) if we would have a more extreme scenario?
What is the lifetime of a typed HttpClient instance from IHttpClientFactory where the type that will receive it is registered as "AddScoped"?
If you look at the related source codes then you can see that
the factories are registered as Singleton
like IHttpClientFactory, IHttpMessageHandlerFactory
the named clients as Transient
and the typed clients as Transient.
Is this behaviour correct? Shouldn't the HttpClient configuration (e.g. Base Address) be cached somehow or saved somewhere, since it is typed?
The AddHttpClient does not provide an explicit interface to set the BaseAddress. Rather it allows the consumer of the API to specify a method (Action<HttpClient> configureClient) to configure the HttpClient as (s)he wishes.
So, the BaseAddress is not cached. The HttpClient's life cycle is also short, but the underlying HttpClientMessageHandlers are pooled. (related source code)
Manages the pooling and lifetime of underlying HttpClientMessageHandler instances. Automatic management avoids common DNS (Domain Name System) problems that occur when manually managing HttpClient lifetimes
Side-note: there is a cache inside DefaultTypedHttpClientFactory which helps the creation of the typed http clients.
Wouldn't it create some GC pressure (lots of clients being created for the same type) if we would have a more extreme scenario?
As it was discussed above your typed clients and HttpClients come and go. The underlying HttpMessageHandlers are pooled.
Most probably you will first hit the limit of the outgoing concurrent calls rather than causing too much pressure on the GC. But with some stress testing you can make sure which issue hits first.
There is also a cleanup process which runs every 10 seconds by default.

What should the lifetime of RestSharp client wrapper be?

During the process of migrating our application to the new RestSharp version, we notice that the documentation recommends the following usage:
public class GitHubClient {
readonly RestClient _client;
public GitHubClient() {
_client = new RestClient("https://api.github.com/")
.AddDefaultHeader(KnownHeaders.Accept, "application/vnd.github.v3+json");
}
public Task<GitHubRepo[]> GetRepos()
=> _client.GetAsync<GitHubRepo[]>("users/aspnet/repos");
}
Considering that new RestClient() under the hood does new HttpClient(handler), should GitHubClient be a Singleton? Or its lifetime shouldn't have any impact at all?
Normally, an API client would be registered as a singleton as it must be thread-safe. In that case, the wrapped instance of RestClient, as well as its internal HttpMessageHandler (HttpClient is not that important here), will be a singleton.
Basically, a plethora of issues of RestSharp was related to its use of the legacy HttpWebRequest, which had a primitive HttpClient caching inside. RestRequest, and, consequently, HttpWebRequest, used to have a number of properties that triggered instantiation of a new HttpMessageHandler when those properties were changed. And that caused all the issues you can possibly imagine, which are retailed in Microsoft docs.
Your question reminded me that HttpClient is disposable, but the current RestClient is not (as per v107.0.4), so I will add it in the next patch.

Is it fine to use one HttpClient instance for each host my application needs to talk to?

I know that, when using the Microsoft dependency injection container, the best practice to handle HttpClient instances is using the IHttpClientFactory interface provided by the Microsoft.Extensions.Http nuget package.
Unfortunately the classes implementing the IHttpClientFactory interface are not public (as you can verify here), so the only way to exploit this pattern is using the Microsoft dependency injection container (at least it's the only one that I know). Sometimes I need to maintain old applications using a different container, so I need to figure out a best practice even when the IHttpClientFactory approach cannot be used.
As explained in this famous article and confirmed in the Microsoft docs too the HttpClient class is designed to be instantiated once per application lifetime and reused across multiple HTTP calls. This can safely be done because the public methods used to issue HTTP calls are documented to be thread safe, so a singleton instance can be safely used. In this case, it is important to follow the tips given in this article in order to avoid issues related with DNS changes.
So far so good.
Sometimes it is handy to use properties like BaseAddress or DefaultRequestHeaders, which are not thread safe (at least, they are not documented to be thread safe, so I assume they are not) to configure the HttpClient instance.
This opens a question: what happens if I have a singleton HttpClient instance and somewhere in my code I use the property DefaultRequestHeaders to set some common HTTP request headers useful to call one of the host my application needs to communicate with ? This is potentially dangerous, because different hosts could require different values for the same request header (think of authentication as an example of that). Furthermore, modifying DefaultRequestHeaders concurrently from two threads could potentially mess up the internal state of the HttpClient instance, because of the lack of thread safety guarantees.
For all these reasons, I think that the best approach to use HttpClient (when IServiceCollection is not available) is the following:
create one instace of HttpClient for each host the application
needs to communicate with. Every call to one specific host will
then use the same instance of HttpClient. Concurrent calls to the
same host are safe, because of the documented thread safety of
methods used to perform calls.
create one service for each host the application needs to
communicate with. The HttpClient instance is injected inside this
service and the service itself is used as a singleton in the
application. This service is used to abstract away the access to the
host it is coupled with. Classes like this are fully testable as illustrated here.
the only point where instances of HttpClient are created and configured is the composition root of the application. The code in the composition root is single threaded, so it is safe to use properties like DefaultRequestHeaders to configure the HttpClient instances.
Do you see any problem in creating one instance of HttpClient per host to be called ?
I know that instantiating one HttpClient per request can lead to socket exhaustion and must be avoided, but I guess that having one instance per host is safe with regard to this problem (because the same instance is used for all the requests to the same host and I do not expect that a single application needs to talk with a large number of different hosts).
Do you agree ? Am I missing anything ?
I know that, when using the Microsoft dependency injection container, the best practice to handle HttpClient instances is using the IHttpClientFactory interface provided by the Microsoft.Extensions.Http nuget package.
Correct.
Unfortunately the classes implementing the IHttpClientFactory interface are not public (as you can verify here), so the only way to exploit this pattern is using the Microsoft dependency injection container (at least it's the only one that I know). Sometimes I need to maintain old applications using a different container, so I need to figure out a best practice even when the IHttpClientFactory approach cannot be used.
Microsoft.Extensions.DependencyInjection ("MEDI") should be thought of a (simplistic) abstraction over multiple DI systems - it just so happens to come with its own basic DI container. You can use MEDI as a front for Unity, SimpleInject, Ninject, and others.
As explained in this famous article and confirmed in the Microsoft docs too the HttpClient class is designed to be instantiated once per application lifetime and reused across multiple HTTP calls.
Not exactly.
You don't want a singleton HttpClient used by all consumers of HttpClient in your application because different consumers might have different assumptions about (as you later point out) DefaultRequestHeaders and other HttpClient state. Some code may also assume that HttpClient is not using any DelegatingHandler instances either.
You also don't want any instances of HttpClient (created using its own parameterless constructor) with an unlimited lifetime because of how its default internal HttpClientHandler handles (or rather, doesn't handle) DNS changes. Hence why the default IHttpClientFactory imposes a lifetime limit of 2 minutes for each HttpClientHandler instance.
This opens a question: what happens if I have a singleton HttpClient instance and somewhere in my code I use the property DefaultRequestHeaders to set some common HTTP request headers useful to call one of the host my application needs to communicate with?
What happens? What happens is what you can expect: different consumers of the same HttpClient instance acting on wrong information - such as sending the wrong Authorization header to the wrong BaseAddress. This is why HttpClient instances should not be shared.
This is potentially dangerous, because different hosts could require different values for the same request header (think of authentication as an example of that). Furthermore, modifying DefaultRequestHeaders concurrently from two threads could potentially mess up the internal state of the HttpClient instance, because of the lack of thread safety guarantees.
This isn't necessarily a "Thread safety" issue - you can have a single-threaded application that abuses a singleton HttpClient this way and still have the same issue. The real issue is that different objects (the consumers of HttpClient) are assuming that they are the owner of the HttpClient when they aren't.
Unfortunately C# and .NET do not have a built-in way to declare and assert ownership or object lifetimes (hence why IDisposable is a bit of a mess today) - so we need to resort to different alternatives.
create one instace of HttpClient for each host the application needs to communicate with. Every call to one specific host will then use the same instance of HttpClient. Concurrent calls to the same host are safe, because of the documented thread safety of methods used to perform calls.
(By "host" I assume you mean HTTP "origin"). This is naive and won't work if you make different requests to the same service with different access-tokens (if the access-tokens are stored in DefaultRequestHeaders).
create one service for each host the application needs to communicate with. The HttpClient instance is injected inside this service and the service itself is used as a singleton in the application. This service is used to abstract away the access to the host it is coupled with. Classes like this are fully testable as illustrated here.
Again, don't think of HTTP services in terms of "hosts" - otherwise this has the same problem as above.
the only point where instances of HttpClient are created and configured is the composition root of the application. The code in the composition root is single threaded, so it is safe to use properties like DefaultRequestHeaders to configure the HttpClient instances.
I'm not sure how this helps either. Your consumers might be stateful.
Anyway, the real solution, imo, is to implement your own IHttpClientFactory (it can also be your own interface!). To simplify things, your consumers' constructors won't accept a HttpClient instance, but instead accept the IHttpClientFactory and call its CreateClient method in order to get their own privately-owned and stateful instance of HttpClient which then uses the pool of shared and stateless HttpClientHandler instances.
Using this approach:
Each consumer gets its own private instance of HttpClient that they can alter as they like - no worries about objects modifying instances that they don't own.
Each consumer's HttpClient instance does not need to be disposed - you can safely disregard the fact they implement IDisposable.
Without pooled handlers, each HttpClient instance owns its own handler, which must be disposed.
But with pooled handlers, as with this approach, the pool manages handler lifetime and clean-up, not the HttpClient instances.
Your code can call HttpClient.Dispose() if it really wants to (or you just want to make FxCop shut-up) but it wont do anything: the underlying HttpMessageHandler (PooledHttpClientHandler) has a NOOP dispose method.
Managing the lifetime of HttpClient is irrelevant because each HttpClient only owns its own mutable state like DefaultRequestHeaders and BaseAddress - so you can have transient, scoped, long-life'd or singleton HttpClient instances and it's okay because they all dip into the pool of HttpClientHandler instances only when they actually send a request.
Like so:
/// <summary>This service should be registered as a singleton, or otherwise have an unbounded lifetime.</summary>
public QuickAndDirtyHttpClientFactory : IHttpClientFactory // `IHttpClientFactory ` can be your own interface. You do NOT need to use `Microsoft.Extensions.Http`.
{
private readonly HttpClientHandlerPool pool = new HttpClientHandlerPool();
public HttpClient CreateClient( String name )
{
PooledHttpClientHandler pooledHandler = new PooledHttpClientHandler( name, this.pool );
return new HttpClient( pooledHandler );
}
// Alternative, which allows consumers to set up their own DelegatingHandler chains without needing to configure them during DI setup.
public HttpClient CreateClient( String name, Func<HttpMessageHandler, DelegatingHandler> createHandlerChain )
{
PooledHttpClientHandler pooledHandler = new PooledHttpClientHandler( name, this.pool );
DelegatingHandler chain = createHandlerChain( pooledHandler );
return new HttpClient( chain );
}
}
internal class HttpClientHandlerPool
{
public HttpClientHandler BorrowHandler( String name )
{
// Implementing this is an exercise for the reader.
// Alternatively, I'm available as a consultant for a very high hourly rate :D
}
public void ReleaseHandler( String name, HttpClientHandler handler )
{
// Implementing this is an exercise for the reader.
}
}
internal class PooledHttpClientHandler : HttpMessageHandler
{
private readonly String name;
private readonly HttpClientHandlerPool pool;
public PooledHttpClientHandler( String name, HttpClientHandlerPool pool )
{
this.name = name;
this.pool = pool ?? throw new ArgumentNullException(nameof(pool));
}
protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken )
{
HttpClientHandler handler = this.pool.BorrowHandler( this.name );
try
{
return await handler.SendAsync( request, cancellationToken ).ConfigureAwait(false);
}
finally
{
this.pool.ReleaseHandler( this.name, handler );
}
}
// Don't override `Dispose(Bool)` - don't need to.
}
Then each consuimer can use it like so:
public class Turboencabulator : IEncabulator
{
private readonly HttpClient httpClient;
public Turboencabulator( IHttpClientFactory hcf )
{
this.httpClient = hcf.CreateClient();
this.httpClient.DefaultRequestHeaders.Add( "Authorization", "my-secret-bearer-token" );
this.httpClient.BaseAddress = "https://api1.example.com";
}
public async InverseReactiveCurrent( UnilateralPhaseDetractor upd )
{
await this.httpClient.GetAsync( etc )
}
}
public class SecretelyDivertDataToTheNsaEncabulator : IEncabulator
{
private readonly HttpClient httpClientReal;
private readonly HttpClient httpClientNsa;
public SecretNsaClientService( IHttpClientFactory hcf )
{
this.httpClientReal = hcf.CreateClient();
this.httpClientReal.DefaultRequestHeaders.Add( "Authorization", "a-different-secret-bearer-token" );
this.httpClientReal.BaseAddress = "https://api1.example.com";
this.httpClientNsa = hcf.CreateClient();
this.httpClientNsa.DefaultRequestHeaders.Add( "Authorization", "TODO: it's on a postit note on my desk viewable from outside the building" );
this.httpClientNsa.BaseAddress = "https://totallylegit.nsa.gov";
}
public async InverseReactiveCurrent( UnilateralPhaseDetractor upd )
{
await this.httpClientNsa.GetAsync( etc )
await this.httpClientReal.GetAsync( etc )
}
}

Do I have to dispose HTTP client at all? [duplicate]

System.Net.Http.HttpClient and System.Net.Http.HttpClientHandler in .NET Framework 4.5 implement IDisposable (via System.Net.Http.HttpMessageInvoker).
The using statement documentation says:
As a rule, when you use an IDisposable object, you should declare and
instantiate it in a using statement.
This answer uses this pattern:
var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("foo", "bar"),
new KeyValuePair<string, string>("baz", "bazinga"),
});
cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
var result = client.PostAsync("/test", content).Result;
result.EnsureSuccessStatusCode();
}
But the most visible examples from Microsoft don't call Dispose() either explicitly or implicitly. For instance:
The original blog article announcing the relase of HttpClient.
The actual MSDN documentation for HttpClient.
BingTranslateSample
GoogleMapsSample
WorldBankSample
In the announcement's comments, someone asked the Microsoft employee:
After checking your samples, I saw that you didn't perform the dispose
action on HttpClient instance. I have used all instances of HttpClient
with using statement on my app and I thought that it is the right way
since HttpClient implements the IDisposable interface. Am I on the
right path?
His answer was:
In general that is correct although you have to be careful with
"using" and async as they dont' really mix in .Net 4, In .Net 4.5 you
can use "await" inside a "using" statement.
Btw, you can reuse the same HttpClient as many times are [as] you like so
typically you won't create/dispose them all the time.
The second paragraph is superfluous to this question, which is not concerned about how many times you can use an HttpClient instance, but about if it is necessary to dispose it after you no longer need it.
(Update: in fact that second paragraph is the key to the answer, as provided below by #DPeden.)
So my questions are:
Is it necessary, given the current implementation (.NET Framework 4.5), to call Dispose() on HttpClient and HttpClientHandler instances? Clarification: by "necessary" I mean if there are any negative consequences for not disposing, such as resource leakage or data corruption risks.
If it's not necessary, would it be a "good practice" anyway, since they implement IDisposable?
If it's necessary (or recommended), is this code mentioned above implementing it safely (for .NET Framework 4.5)?
If these classes don't require calling Dispose(), why were they implemented as IDisposable?
If they require, or if it's a recommended practice, are the Microsoft examples misleading or unsafe?
The general consensus is that you do not (should not) need to dispose of HttpClient.
Many people who are intimately involved in the way it works have stated this.
See Darrel Miller's blog post and a related SO post: HttpClient crawling results in memory leak for reference.
I'd also strongly suggest that you read the HttpClient chapter from Designing Evolvable Web APIs with ASP.NET for context on what is going on under the hood, particularly the "Lifecycle" section quoted here:
Although HttpClient does indirectly implement the IDisposable
interface, the standard usage of HttpClient is not to dispose of it
after every request. The HttpClient object is intended to live for as
long as your application needs to make HTTP requests. Having an object
exist across multiple requests enables a place for setting
DefaultRequestHeaders and prevents you from having to re-specify
things like CredentialCache and CookieContainer on every request as
was necessary with HttpWebRequest.
Or even open up DotPeek.
The current answers are a bit confusing and misleading, and they are missing some important DNS implications. I'll try to summarize where things stand clearly.
Generally speaking most IDisposable objects should ideally be disposed when you are done with them, especially those that own Named/shared OS resources. HttpClient is no exception, since as Darrel Miller points out it allocates cancellation tokens, and request/response bodies can be unmanaged streams.
However, the best practice for HttpClient says you should create one instance and reuse it as much as possible (using its thread-safe members in multi-threaded scenarios). Therefore, in most scenarios you'll never dispose of it simply because you will be needing it all the time.
The problem with re-using the same HttpClient "forever" is that the underlying HTTP connection might remain open against the originally DNS-resolved IP, regardless of DNS changes. This can be an issue in scenarios like blue/green deployment and DNS-based failover. There are various approaches for dealing with this issue, the most reliable one involving the server sending out a Connection:close header after DNS changes take place. Another possibility involves recycling the HttpClient on the client side, either periodically or via some mechanism that learns about the DNS change. See https://github.com/dotnet/corefx/issues/11224 for more information (I suggest reading it carefully before blindly using the code suggested in the linked blog post).
Since it doesn't appear that anyone has mentioned it here yet, the new best way to manage HttpClient and HttpClientHandler in .NET Core >=2.1 and .NET 5.0+ is using HttpClientFactory.
It solves most of the aforementioned issues and gotchas in a clean and easy-to-use way. From Steve Gordon's great blog post:
Add the following packages to your .Net Core (2.1.1 or later) project:
Microsoft.AspNetCore.All
Microsoft.Extensions.Http
Add this to Startup.cs:
services.AddHttpClient();
Inject and use:
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<ActionResult> Get()
{
var client = _httpClientFactory.CreateClient();
var result = await client.GetStringAsync("http://www.google.com");
return Ok(result);
}
}
Explore the series of posts in Steve's blog for lots more features.
In my understanding, calling Dispose() is necessary only when it's locking resources you need later (like a particular connection). It's always recommended to free resources you're no longer using, even if you don't need them again, simply because you shouldn't generally be holding onto resources you're not using (pun intended).
The Microsoft example is not incorrect, necessarily. All resources used will be released when the application exits. And in the case of that example, that happens almost immediately after the HttpClient is done being used. In like cases, explicitly calling Dispose() is somewhat superfluous.
But, in general, when a class implements IDisposable, the understanding is that you should Dispose() of its instances as soon as you're fully ready and able. I'd posit this is particularly true in cases like HttpClient wherein it's not explicitly documented as to whether resources or connections are being held onto/open. In the case wherein the connection will be reused again [soon], you'll want to forgo Dipose()ing of it -- you're not "fully ready" in that case.
See also:
IDisposable.Dispose Method and When to call Dispose
Short answer: No, the statement in the currently accepted answer is NOT accurate: "The general consensus is that you do not (should not) need to dispose of HttpClient".
Long answer: BOTH of the following statements are true and achieveable at the same time:
"HttpClient is intended to be instantiated once and re-used throughout the life of an application", quoted from official documentation.
An IDisposable object is supposed/recommended to be disposed.
And they DO NOT NECESSARILY CONFLICT with each other. It is just a matter of how you organize your code to reuse an HttpClient AND still dispose it properly.
An even longer answer quoted from my another answer:
It is not a coincidence to see people
in some blog posts blaming how HttpClient 's IDisposable interface
makes them tend to use the using (var client = new HttpClient()) {...} pattern
and then lead to exhausted socket handler problem.
I believe that comes down to an unspoken (mis?)conception:
"an IDisposable object is expected to be short-lived".
HOWEVER, while it certainly looks like a short-lived thing when we write code in this style:
using (var foo = new SomeDisposableObject())
{
...
}
the official documentation on IDisposable
never mentions IDisposable objects have to be short-lived.
By definition, IDisposable is merely a mechanism to allow you to release unmanaged resources.
Nothing more. In that sense, you are EXPECTED to eventually trigger the disposal,
but it does not require you to do so in a short-lived fashion.
It is therefore your job to properly choose when to trigger the disposal,
base on your real object's life cycle requirement.
There is nothing stopping you from using an IDisposable in a long-lived way:
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
With this new understanding, now we revisit that blog post,
we can clearly notice that the "fix" initializes HttpClient once but never dispose it,
that is why we can see from its netstat output that,
the connection remains at ESTABLISHED state which means it has NOT been properly closed.
If it were closed, its state would be in TIME_WAIT instead.
In practice, it is not a big deal to leak only one connection open after your entire program ends,
and the blog poster still see a performance gain after the fix;
but still, it is conceptually incorrect to blame IDisposable and choose to NOT dispose it.
Dispose() calls the code below, which closes the connections opened by the HttpClient instance. The code was created by decompiling with dotPeek.
HttpClientHandler.cs - Dispose
ServicePointManager.CloseConnectionGroups(this.connectionGroupName);
If you don't call dispose then ServicePointManager.MaxServicePointIdleTime, which runs by a timer, will close the http connections. The default is 100 seconds.
ServicePointManager.cs
internal static readonly TimerThread.Callback s_IdleServicePointTimeoutDelegate = new TimerThread.Callback(ServicePointManager.IdleServicePointTimeoutCallback);
private static volatile TimerThread.Queue s_ServicePointIdlingQueue = TimerThread.GetOrCreateQueue(100000);
private static void IdleServicePointTimeoutCallback(TimerThread.Timer timer, int timeNoticed, object context)
{
ServicePoint servicePoint = (ServicePoint) context;
if (Logging.On)
Logging.PrintInfo(Logging.Web, SR.GetString("net_log_closed_idle", (object) "ServicePoint", (object) servicePoint.GetHashCode()));
lock (ServicePointManager.s_ServicePointTable)
ServicePointManager.s_ServicePointTable.Remove((object) servicePoint.LookupString);
servicePoint.ReleaseAllConnectionGroups();
}
If you haven't set the idle time to infinite then it appears safe not to call dispose and let the idle connection timer kick-in and close the connections for you, although it would be better for you to call dispose in a using statement if you know you are done with an HttpClient instance and free up the resources faster.
In my case, I was creating an HttpClient inside a method that actually did the service call. Something like:
public void DoServiceCall() {
var client = new HttpClient();
await client.PostAsync();
}
In an Azure worker role, after repeatedly calling this method (without disposing the HttpClient), it would eventually fail with SocketException (connection attempt failed).
I made the HttpClient an instance variable (disposing it at the class level) and the issue went away. So I would say, yes, dispose the HttpClient, assuming its safe (you don't have outstanding async calls) to do so.
In typical usage (responses<2GB) it is not necessary to Dispose the HttpResponseMessages.
The return types of the HttpClient methods should be Disposed if their Stream Content is not fully Read. Otherwise there is no way for the CLR to know those Streams can be closed until they are garbage collected.
If you are reading the data into a byte[] (e.g. GetByteArrayAsync) or string, all data is read, so there is no need to dispose.
The other overloads will default to reading the Stream up to 2GB (HttpCompletionOption is ResponseContentRead, HttpClient.MaxResponseContentBufferSize default is 2GB)
If you set the HttpCompletionOption to ResponseHeadersRead or the response is larger than 2GB, you should clean up. This can be done by calling Dispose on the HttpResponseMessage or by calling Dispose/Close on the Stream obtained from the HttpResonseMessage Content or by reading the content completely.
Whether you call Dispose on the HttpClient depends on whether you want to cancel pending requests or not.
If you want to dispose of HttpClient, you can if you set it up as a resource pool. And at the end of your application, you dispose your resource pool.
Code:
// Notice that IDisposable is not implemented here!
public interface HttpClientHandle
{
HttpRequestHeaders DefaultRequestHeaders { get; }
Uri BaseAddress { get; set; }
// ...
// All the other methods from peeking at HttpClient
}
public class HttpClientHander : HttpClient, HttpClientHandle, IDisposable
{
public static ConditionalWeakTable<Uri, HttpClientHander> _httpClientsPool;
public static HashSet<Uri> _uris;
static HttpClientHander()
{
_httpClientsPool = new ConditionalWeakTable<Uri, HttpClientHander>();
_uris = new HashSet<Uri>();
SetupGlobalPoolFinalizer();
}
private DateTime _delayFinalization = DateTime.MinValue;
private bool _isDisposed = false;
public static HttpClientHandle GetHttpClientHandle(Uri baseUrl)
{
HttpClientHander httpClient = _httpClientsPool.GetOrCreateValue(baseUrl);
_uris.Add(baseUrl);
httpClient._delayFinalization = DateTime.MinValue;
httpClient.BaseAddress = baseUrl;
return httpClient;
}
void IDisposable.Dispose()
{
_isDisposed = true;
GC.SuppressFinalize(this);
base.Dispose();
}
~HttpClientHander()
{
if (_delayFinalization == DateTime.MinValue)
_delayFinalization = DateTime.UtcNow;
if (DateTime.UtcNow.Subtract(_delayFinalization) < base.Timeout)
GC.ReRegisterForFinalize(this);
}
private static void SetupGlobalPoolFinalizer()
{
AppDomain.CurrentDomain.ProcessExit +=
(sender, eventArgs) => { FinalizeGlobalPool(); };
}
private static void FinalizeGlobalPool()
{
foreach (var key in _uris)
{
HttpClientHander value = null;
if (_httpClientsPool.TryGetValue(key, out value))
try { value.Dispose(); } catch { }
}
_uris.Clear();
_httpClientsPool = null;
}
}
var handler = HttpClientHander.GetHttpClientHandle(new Uri("base url")).
HttpClient, as an interface, can't call Dispose().
Dispose() will be called in a delayed fashion by the Garbage Collector.
Or when the program cleans up the object through its destructor.
Uses Weak References + delayed cleanup logic so it remains in use so long as it is being reused frequently.
It only allocates a new HttpClient for each base URL passed to it. Reasons explained by Ohad Schneider answer below. Bad behavior when changing base url.
HttpClientHandle allows for Mocking in tests
Using dependency injection in your constructor makes managing the lifetime of your HttpClient easier - taking the lifetime managemant outside of the code that needs it and making it easily changable at a later date.
My current preference is to create a seperate http client class that inherits from HttpClient once per target endpoint domain and then make it a singleton using dependency injection. public class ExampleHttpClient : HttpClient { ... }
Then I take a constructor dependency on the custom http client in the service classes where I need access to that API. This solves the lifetime problem and has advantages when it comes to connection pooling.
You can see a worked example in related answer at https://stackoverflow.com/a/50238944/3140853
No, don't create a new one on every request (even if you dispose of the old ones). You will cause the server itself (not just the application) to crash because of port exhaustion at the network level on the Operating System!
Please take a read on my answer to a very similar question posted below. It should be clear that you should treat HttpClient instances as singletons and re-used across requests.
What is the overhead of creating a new HttpClient per call in a WebAPI client?
I think one should use singleton pattern to avoid having to create instances of the HttpClient and closing it all the time. If you are using .Net 4.0 you could use a sample code as below. for more information on singleton pattern check here.
class HttpClientSingletonWrapper : HttpClient
{
private static readonly Lazy<HttpClientSingletonWrapper> Lazy= new Lazy<HttpClientSingletonWrapper>(()=>new HttpClientSingletonWrapper());
public static HttpClientSingletonWrapper Instance {get { return Lazy.Value; }}
private HttpClientSingletonWrapper()
{
}
}
Use the code as below.
var client = HttpClientSingletonWrapper.Instance;

Singleton httpclient vs creating new httpclient request

I am trying to create layer for webservice using HttpClient in my Xamarin.Forms mobile app.
without singlton pattern
with singleton pattern
in first approach i am creating new http client object in each new request made
by mobile applicaiton.
here is my code
public HttpClient GetConnection()
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(baseAddress);
httpClient.Timeout = System.TimeSpan.FromMilliseconds(timeout);
return httpClient;
}
post request code
public async Task<TResult> PostAsync<TRequest, TResult>(String url, TRequest requestData)
{
HttpClient client = GetConnection();
String responseData = null;
if (client != null)
{
String serializedObject = await Task.Run(() => JsonConvert.SerializeObject(requestData, _jsonSerializerSettings));
var jsonContent = new StringContent(serializedObject, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(new Uri(url, UriKind.Relative), jsonContent);
responseData = await HandleResponse(response);
return await Task.Run(() => JsonConvert.DeserializeObject<TResult>(responseData, _jsonSerializerSettings));
}
else
{
throw new NullReferenceException("NullReferenceException # PostAsync httpclient is null WebRequest.cs");
}
}
client will use following code to execute request
new LoginService(new WebRequest()).UserLogin(userRequest);
inside class that implements IWebRequest
_webRequest.PostAsync<UserRequest,bool>(Constants.USER_LOGIN, userRequest);
in second approach i am reusing the same http client object in each new request
here , my singleton class is thread safe too.
private static readonly Lazy<HttpService> lazy =
new Lazy<HttpService>(() => new HttpService());
public static HttpService Instance { get { return lazy.Value; } }
private HttpClient getConnection()
{
client = new HttpClient();
client.Timeout = System.TimeSpan.FromMilliseconds(timeout);
//client.MaxResponseContentBufferSize = 500000;
client.BaseAddress = new Uri(baseAddress);
return client;
}
post request code
public Task<HttpResponseMessage> sendData(String url,String jsonData)
{
var jsonContent = new StringContent(jsonData, System.Text.Encoding.UTF8, "application/json");
return getConnection().PostAsync(new Uri(url, UriKind.Relative), jsonContent);
}
client will use following code to execute
HttpService.Instance.sendData(...)
i have gone through many libraries like RestSharp over web just to explore the best and i found that most of them are creating new objects per request. so i am confused which pattern fits best.
Update: It seems that using a single static instance of HttpClient doesn't respect DNS changes, so the solution is to use HttpClientFactory. See here for Microsoft docs about it.
To use the HttpClientFactory you have to use Microsoft's dependency injection. This is the default for ASP.NET Core projects, but for others you will have to reference Microsoft.Extensions.Http and Microsoft.Extensions.DependencyInjection.
Then when you're creating your service container, you simply call AddHttpClient():
var services = new ServiceCollection();
services.AddHttpClient()
var serviceProvider = services.BuildServiceProvider();
And then you can inject IHttpClientFactory into your services, and behind the scenes HttpClientFactory will maintain a pool of HttpClientHandler objects - keeping your DNS fresh and preventing problems with connection pool exhaustion.
Old answer:
Singleton is the correct way to use HttpClient. Please see this article for full details.
Microsoft docs state:
HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors. Below is an example using HttpClient correctly.
And indeed, we found this in our application. We have code that can potentially make hundreds of API requests in a foreach loop, and for each iteration we were creating an HttpClient wrapped in a using. We soon started getting red herring errors from our MongoClient saying that it had timed out trying to connect to the database. After reading the linked article, we found that even after disposing of HttpClient, and realised that we were exhausting the available sockets.
The only thing to note is that things like DefaultRequestHeaders and BaseAddress will be applied anywhere that HttpClient is used. As a singleton, this is potentially throughout the application. You can still create multiple HttpClient instances in your application, but just be aware that each time you do, they create a new connection pool and, as such, should be created sparingly.
As pointed out by hvaughan3, you also can't change the instance of HttpMessageHandler used by the HttpClient, so if this matters to you, you would need to use a separate instance with that handler.
While HttpClient is supposed to be reused, it does not necessarily mean we have to use singleton to organize our code. Please refer to my answer here. Also quoted below.
I'm late to the party, but here is my learning journey on this tricky topic.
1. Where can we find the official advocate on reusing HttpClient?
I mean, if reusing HttpClient is intended
and doing so is important,
such advocate is better documented in its own API documentation,
rather than being hidden in lots of "Advanced Topics", "Performance (anti)pattern"
or other blog posts out there.
Otherwise how is a new learner supposed to know it before it is too late?
As of now (May 2018), the first search result when googling "c# httpclient"
points to this API reference page on MSDN, which does not mention that intention at all.
Well, lesson 1 here for newbie is,
always click the "Other Versions" link right after the MSDN help page headline,
you will probably find links to the "current version" there.
In this HttpClient case, it will bring you to the latest document
here containing that intention description.
I suspect many developers who was new to this topic
did not find the correct documentation page either,
that's why this knowledge is not widely spread,
and people were surprised when they found it out
later,
possibly in a hard way.
2. The (mis?)conception of using IDisposable
This one is slightly off-topic but still worth pointing out that, it is not a coincidence to see people
in those aforementioned blog posts blaming how HttpClient 's IDisposable interface
makes them tend to use the using (var client = new HttpClient()) {...} pattern
and then lead to the problem.
I believe that comes down to an unspoken (mis?)conception:
"an IDisposable object is expected to be short-lived".
HOWEVER, while it certainly looks like a short-lived thing when we write code in this style:
using (var foo = new SomeDisposableObject())
{
...
}
the official documentation on IDisposable
never mentions IDisposable objects have to be short-lived.
By definition, IDisposable is merely a mechanism to allow you to release unmanaged resources.
Nothing more. In that sense, you are EXPECTED to eventually trigger the disposal,
but it does not require you to do so in a short-lived fashion.
It is therefore your job to properly choose when to trigger the disposal,
base on your real object's life cycle requirement.
There is nothing stopping you from using an IDisposable in a long-lived way:
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
With this new understanding, now we revisit that blog post,
we can clearly notice that the "fix" initializes HttpClient once but never dispose it,
that is why we can see from its netstat output that,
the connection remains at ESTABLISHED state which means it has NOT been properly closed.
If it were closed, its state would be in TIME_WAIT instead.
In practice, it is not a big deal to leak only one connection open after your entire program ends,
and the blog poster still see a performance gain after the fix;
but still, it is conceptually incorrect to blame IDisposable and choose to NOT dispose it.
3. Do we have to put HttpClient into a static property, or even put it as a singleton?
Based on the understanding of the previous section,
I think the answer here becomes clear: "not necessarily".
It really depends on how you organize your code,
as long as you reuse an HttpClient AND (ideally) dispose it eventually.
Hilariously, not even the example in the
Remarks section of the current official document
does it strictly right. It defines a "GoodController" class,
containing a static HttpClient property that will not be disposed;
which disobeys what another example in the Examples section
emphasizes: "need to call dispose ... so app doesn't leak resources".
And lastly, singleton is not without its own challenges.
"How many people think global variable is a good idea? No one.
How many people think singleton is a good idea? A few.
What gives? Singletons are just a bunch of global variables."
-- Quoted from this inspiring talk, "Global State and Singletons"
PS: SqlConnection
This one is irrelevant to the current Q&A, but it is probably a good-to-know.
SqlConnection usage pattern is different.
You do NOT need to reuse SqlConnection,
because it will handle its connection pool better that way.
The difference is caused by their implementation approach.
Each HttpClient instance uses its own connection pool (quoted from
here);
but SqlConnection itself is managed by a central connection pool,
according to this.
And you still need to dispose SqlConnection, same as you are supposed to do for HttpClient.
.NET Core 2.1+
When you can use DI:
using System.Net.Http;
public class SomeClass
{
private readonly IHttpClientFactory _httpClientFactory;
public SomeClass(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public void Foo()
{
var httpClient = _httpClientFactory.CreateClient();
...
}
}
When you can't use DI:
using System.Net.Http;
public class SomeClass
{
private static readonly HttpClient Client;
static SomeClass()
{
var handler = new SocketsHttpHandler
{
// Sets how long a connection can be in the pool to be considered reusable (by default - infinite)
PooledConnectionLifetime = TimeSpan.FromMinutes(1),
};
Client = new HttpClient(handler, disposeHandler: false);
}
...
}
Reference https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0#alternatives-to-ihttpclientfactory
As others mentioned, mostly HttpClient should be used as singleton, but there is one exception - you should not use HttpClient as singleton when you use HTTP long polling technique, because you will block other requests execution.
For long polling requests you should create separate HttpClient.
If you will use HttpClient as static property in WebApi applicaion, you can get following error
System.InvalidOperationException: Concurrent reads or writes are not supported.\r\n at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()\r\n at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)\r\n at System.IO.Pipelines.Pipe.GetReadAsyncResult()\r\n at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext.WriteBody(Boolean flush)","ClassName":"IISHttpContext","MethodName":"WriteBody","EventId":{"Id":3,"Name":"UnexpectedError"},"SourceContext":"Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer"
Error will appear, when inside of you action in webapi controller you are making 2 concurrent requests to same url using HttpClient static instance
therefore i think usage of
_httpClientFactory.CreateClient(Guid.NewGuid().ToString()) in action is most safe approach. According to documentation of the method -
" It is generally not necessary to dispose of the System.Net.Http.HttpClient as the System.Net.Http.IHttpClientFactory tracks and disposes resources used by the System.Net.Http.HttpClient."

Categories

Resources