412

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:

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:

  1. 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.

  2. If it's not necessary, would it be a "good practice" anyway, since they implement IDisposable?

  3. If it's necessary (or recommended), is this code mentioned above implementing it safely (for .NET Framework 4.5)?

  4. If these classes don't require calling Dispose(), why were they implemented as IDisposable?

  5. If they require, or if it's a recommended practice, are the Microsoft examples misleading or unsafe?

Alexander
  • 4,153
  • 1
  • 24
  • 37
Fernando Correia
  • 21,803
  • 13
  • 83
  • 116
  • "If it's not absolutely necessary..." - it's *never* "absolutely necessary" to dispose of any Disposable. In the same way that it's not "absolutely necessary" to dispose of your rubbish responsibly if you're visiting someone else's house. – Damien_The_Unbeliever Mar 29 '13 at 14:52
  • 2
    @Damien_The_Unbeliever, thank you for your feedback. Do you have any suggestions on how I could clarify the question? I want to know if it can lead to the issues generally associated with not disposing of resources, such as resource leakage and data corruption. – Fernando Correia Mar 29 '13 at 14:54
  • 10
    @Damien_The_Unbeliever: Not true. In particular, stream writers must be disposed to have correct behavior. – Stephen Cleary Mar 29 '13 at 14:55
  • I guess I don't see the whole point of the question. You're aware that they do implement the disposable pattern. You're aware of what you (as a good citizen/consumer) are meant to do with a disposable object when you no longer need it. You're also aware that the *expectation* is that one of these objects might be used for multiple requests, so you're unlikely to see examples that just create one, send a single request, and then immediately dispose of it. – Damien_The_Unbeliever Mar 29 '13 at 14:56
  • 1
    @StephenCleary - what aspects are you thinking of? Certainly, you can call `Flush` on one after every write, and other than the inconvenience of it continuing to hold the underlying resources for longer than necessary, what won't occur that is required for "correct behavior"? – Damien_The_Unbeliever Mar 29 '13 at 14:59
  • @Damien_The_Unbeliever in the code I usually write, I create a new HttpClient instance when I need to send a new request instead of keeping that client instance around. I think it sits well with the stateless nature of the HTTP protocol. But I did not usually dispose of these instances, and just today I noticed that they implement IDisposable. That's why I'm trying to find out if I'm expected to dispose them explicitly. I hope that clarifies my question. – Fernando Correia Mar 29 '13 at 15:03
  • There doesn't seem to be an obviously clear answer to this issue. Considering that it must be one of the most used .net classes in the modern internet world I find it quite strange that MSDN has not clearly clarified how it should be used. – Zapnologica Aug 13 '16 at 18:14
  • 2
    This is plain wrong: "As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement". I would read the documentation on the class implementing IDisposable always before deciding whether I should use a using for it. As the author of libraries where I implement IDisposable becuase need to release unmanged resources, i would be horrified if consumers created disposed an instance each time instead of re-using an existing instance. That is not to say don't dispose of instance eventually.. – markmnl Jun 22 '17 at 01:16
  • 1
    I have submitted a PR to microsoft to update their docs: https://github.com/dotnet/docs/pull/2470 – markmnl Jun 22 '17 at 01:34
  • The disposable pattern is required learning for the C# .net 4.5 certification. Some confusion lies in backwards compatibility with .net 2.0 over-using idisposible (such as with memory streams and IEnumerable). You should guarantee dispose gets called immediately after finishing using it for anything that wraps “ external resources”. File are a good example. When a httpClient (per question) reads a file, even if you run flush, a lingering lock is held. On your system GC will clean it up quickly. On another, who knows. Or as your environment changes. Mb one day, it can’t be written to. – TamusJRoyce May 17 '19 at 18:02
  • The new best way to manage HttpClient and HttpClientHandler in .Net Core 2.1: [HttpClientFactory](https://learn.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests). Solves a multitude of potential problems and gotchas. – pcdev Jul 08 '19 at 05:07
  • Here is Microsoft's official post on how to utilize HttpClient properly. https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests – XtremeOwnage Nov 08 '21 at 17:46

12 Answers12

298

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.

torvin
  • 6,515
  • 1
  • 37
  • 52
David Peden
  • 17,596
  • 6
  • 52
  • 72
  • 86
    To clarify your answer, would it be correct to say that "you do not need to dispose of HttpClient IF YOU HOLD ON TO THE INSTANCE TO REUSE IT LATER"? For instance, if a method is called repeatedly and creates a new HttpClient instance (even though it's not the recommended pattern in most cases), would it still be correct to say this method should not dispose the instance (that will not be reused)? It could lead to thousands of undisposed instances. In other words, that you should try and reuse the instances, but if you don't reuse, you'd better dispose them (to release the connections)? – Fernando Correia Apr 03 '13 at 12:22
  • 9
    I think the understandably frustrating but correct answer is it depends. If I had to be pinned to giving general advice that worked in most (I never say all) cases, I would suggest that you use an IoC container and register an instance of HttpClient as a singleton. The lifetime of the instance would then be scoped to that of the lifetime of the container. This could be scoped at the application level or perhaps per request in a web application. – David Peden Apr 03 '13 at 15:56
  • My takeout is that your answer is that the recommended usage pattern is to avoid repeatedly creating and disposing HttpClient instances, but to reuse the same instance throughout the application's lifecycle. So you'll never be "done" with the HttpClient instance until the application terminates. Following this pattern, you'll rarely reach a point where you're "done" using the instance, until the application ends. – Fernando Correia Apr 03 '13 at 17:14
  • 30
    @FernandoCorreia Yes. If for some reason you do repeatedly create and destroy HttpClient instances then yes, you should Dispose it. I'm not suggesting to ignore the IDisposable interface, just trying to encourage people to re-use instances. – Darrel Miller Apr 04 '13 at 01:18
  • 23
    Just to add further credence to this answer, I spoke with the HttpClient team today and they confirmed that HttpClient was not designed to be used per-request. An instance of HttpClient should be kept alive whilst a client application continues to interact with a particular host. – Darrel Miller Sep 17 '14 at 19:54
  • 27
    @DavidPeden Registering HttpClient as a singleton sounds dangerous to me because it's mutable. For example, wouldn't everyone assigning to the `Timeout` property be stomping on each other? – Jon-Eric Sep 16 '15 at 21:55
  • 6
    Also worth noting is a single instance of the HttpClient does not respect DNS changes. See http://byterot.blogspot.se/2016/07/singleton-httpclient-dns.html for details (And https://github.com/dotnet/corefx/issues/11224 for DNS issue in dotnetcore) – GreenMoose Dec 21 '16 at 09:30
  • 2
    And to add to the issues pointed out by @Jon-Eric and @GreenMoose, things like client certificates and custom server certificate validation callback are part of `HttpClient`'s state as well (through its `HttpMessageHandler` constructor parameter). – Timo Aug 20 '18 at 12:47
  • Official Microsoft docs for Framework now say to make a new instance every request: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/httpclient-guidelines#recommended-use >In .NET Framework, create a new HttpClient each time you need to send a request. Which goes against almost all public knowledge which says to use a single static instance. – Red Riding Hood Aug 26 '22 at 15:25
78

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.

  1. 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.
  2. 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.
  3. 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).
Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
  • I dispose it all the time as I can't switch proxy on an instance ;) – ed22 Dec 16 '18 at 00:40
  • 2
    If you do need to dispose the HttpClient for whatever reason, you should keep a static instance of the HttpMessageHandler around, as disposing that one is actually the cause of the issues attributed to disposing the HttpClient. HttpClient has a constructor overload that allows you to specify that the supplied handler should not be disposed, in which case you can reuse the HttpMessageHandler with other HttpClient instances. – Tom Lint Jan 09 '19 at 12:31
  • 2
    You should hold on to your HttpClient, but you can use something like System.Net.ServicePointManager.DnsRefreshTimeout = 3000; This is useful e.g. if you are on a mobile device that at any time may switch between wifi and 4G. – Johan Franzén Mar 26 '19 at 20:46
39

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.

pcdev
  • 2,852
  • 2
  • 23
  • 39
19

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

svidgen
  • 13,744
  • 4
  • 33
  • 58
  • 11
    It's like if someone brings a banana to your house, eats it, and is standing their with the peel. What should they do with the peel? ... If they're on their way out the door with it, let them go. If they're sticking around, make them throw it in the garbage so it doesn't stink the place up. – svidgen Mar 29 '13 at 14:55
  • just to clarify this answer, are you saying, "it's not necessary to dispose if the program is going to end right after you use it"? And that you should dispose if the program is expected to continue for some time doing other things? – Fernando Correia Mar 29 '13 at 14:58
  • @FernandoCorreia Yes, unless I'm forgetting something, I think that's a safe principle. Give it some thought in each case though. If you're working with a connection, for instance, you don't want to `Dispose()` of it prematurely and have to reconnect a few seconds later *if* the existing connection is reusable. Likewise, you don't want to unnecessarily `Dispose()` of images or other structures you might end up having to rebuild in a minute or two. – svidgen Mar 29 '13 at 15:04
  • I understand. But in the particular case of HttpClient and HttpClientHandler which this question is about, are they holding a resource open such as a HTTP connection? If that's what's happening, I might have to rethink my pattern of using them. – Fernando Correia Mar 29 '13 at 15:06
  • @FernandoCorreia See my edit, by the way. I added two resources you can compare my answer to. They give a bit more nuance; but I think my general rule satisfies the recommendations. – svidgen Mar 29 '13 at 15:07
  • @FernandoCorreia Without testing to see whether the connection remains is open (or if the KeepAlive header is sent), the ambiguity would prompt me to favor `Dipose()`ing of the client when it's no longer needed. And, by my general rule, that's sort of my preference even without the ambiguity. And I think that's generally what implementing `IDisposable` suggests: *Call `Dispose()` on me as soon as you're ready to!* – svidgen Mar 29 '13 at 15:13
  • Good reference to the [blog article](http://blogs.msdn.com/b/kimhamil/archive/2008/11/05/when-to-call-dispose.aspx). Even the Microsoft experts agree the issue is confusing. I'll assume HttpClient falls in category 1 (named/shared OS resources) for which the guidance is "if you own it, Dispose it". – Fernando Correia Mar 29 '13 at 15:18
  • This answer is not HttpClient-specific and is incorrect with regard to the claim about the documented behavior. See my answer below. – David Peden Mar 29 '13 at 17:51
  • 1
    @DPeden Your answer isn't at all in conflict with mine. Note, I said, *you should Dispose() of its instances as soon as you're **fully** ready and able*. If you plan on using the instance again, you're not **ready**. – svidgen Mar 29 '13 at 17:56
  • My understanding is that it's technically correct that you should dispose the HttpClient instance after you're done using it. But @DPeden makes a good point, supported by explanations, that the recommended pattern is to keep reusing the same instance. In this sense you'll never be "done" with it, so you won't reach a point where disposing of it becomes a concern. Creating and disposing of HttpClient instances repeatedly is, arguably, an anti-pattern. – Fernando Correia Apr 03 '13 at 17:18
  • @svidgen Be aware that calling Dispose on HttpClientHandler forcibly closes a HTTP Connection that is in the connection pool. This is even if the server returns a Connnection: keep-alive header. The only use I have found for this behavior is on a mobile device there may be some scenarios where you might save power. – Darrel Miller Apr 04 '13 at 01:28
  • @DarrelMiller As I've repeatedly said, it's senseless to dispose of *any* resource you plan on using again [soon]. But, if you're *not* planning on using the connection again [soon], it's bad practice to let it linger. It's an abuse of resources. The rules for an HTTP Connection don't differ, in general, from those of any other connection or resource. – svidgen Apr 10 '13 at 15:26
  • @FernandoCorreia You seem to have the impression that I'm advocating in favor of calling `Dispose()` in all cases -- which I'm not. I'm not sure how I can be more clear. It's good practice to `Dipose()`/free resources you don't need. If you *need* those resources, you obviously shouldn't be `Dispose()`ing of them! – svidgen Apr 10 '13 at 15:28
  • @svidgen By definition "pooled resources" take the responsibility of lifetime management out of the hands of the application. It is the responsibility of ServicePointManager to decide when the TCP connection will be closed, not your application. It is the same for pooled database connections. Closing a DB connection (that is pooled) does not actually close it. – Darrel Miller Apr 10 '13 at 15:33
  • @DarrelMiller Semantics. If your application or thread is holding onto a resource that another application might be able to use, it's your application's responsibility to free that resource when it's no longer needed. Whether this entails closing the connection or simply releasing it for use by another process is irrelevant to the point. – svidgen Apr 10 '13 at 15:38
  • @svidgen I would agree completely if the Dispose method of HttpClientHandler did not go searching in ServicePointManager for a pooled connection associated to the last RequestURI and close it. I have no idea why they implemented this. – Darrel Miller Apr 10 '13 at 16:21
  • @DarrelMiller Likely because they figured there's little to no chance another process is using the same connection or needing the same cookies (I assume it holds onto cookies). So, aside from being a potential security risk to share the connection with other processes, it's "inconsiderate" to leave the connection laying around that no one needs. It's not like a web app's database connection, for instance, wherein everything can use the same connection. It's a web client. Chances are, your process needs something that is irrelevant to other processes. – svidgen Apr 10 '13 at 16:50
14

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:

  1. "HttpClient is intended to be instantiated once and re-used throughout the life of an application", quoted from official documentation.
  2. 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.

RayLuo
  • 17,257
  • 6
  • 88
  • 73
  • thank you for this explanation. It is clearly shed some light toward the consensus. From your opinion, when do you think it is _proper_ to call `HttpClient.Dispose` ?. – Jeson Martajaya May 17 '19 at 16:50
  • @JesonMartajaya, dispose it when your application no longer need to use the httpClient instance. You might think such suggestion sounds vague, but in fact it can perfectly align with the life cycle of your `HttpClient client` variable, which is a Programming-101 thing that you are presumably already doing anyway. You might even be still able to use `using (...) {...}` too. For example, see the Hello World sample inside my answer. – RayLuo May 19 '19 at 00:51
10

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.

Timothy Gonzalez
  • 1,802
  • 21
  • 18
  • 1
    You can also see the code on github. https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs – TamusJRoyce Dec 08 '17 at 20:28
5

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.

David Faivre
  • 2,302
  • 3
  • 23
  • 25
  • Thanks for the feedback. This is a somewhat complex issue. I recommend reading the articles linked in DPeden's answer. In short, the HttpClient instance should be reused throughout the application lifecycle. If you do create new instances repeatedly, you might need to dispose of them. – Fernando Correia Jun 28 '13 at 17:48
  • 7
    "the HttpClient instance should be reused throughout the application lifecycle" this just isnt a good idea with a lot of applications. I'm thinking web applications that use HttpClient. HttpClient holds state (for example the request headers it will use), so one web request thread could easily trample what another is doing. In large web applications I have also seen HttpClient as the problem to major connection problems. When in doubt I say Dispose. – bytedev Jan 07 '16 at 13:47
  • 1
    @nashwan you can't clear headers and add new ones before each request? – Mandeep Janjua Jan 25 '18 at 21:51
  • Microsoft is also recommending to reuse HttpClient instances - https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client – Mandeep Janjua Jan 25 '18 at 22:25
  • @MandeepJanjua that example appears to be a client as a console application. I was referring to a web application being the client. – bytedev Jan 26 '18 at 10:12
  • Hi @nashwan, please find a correct link for web apps here - https://msdn.microsoft.com/en-us/library/system.net.http.httpclient(v=vs.110).aspx#Anchor_5 – Mandeep Janjua Feb 08 '18 at 04:05
  • I also had same issue. Posting more references which support this - 1- https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-5.0 Another one is - https://makolyte.com/csharp-how-to-make-concurrent-requests-with-httpclient/ – Manish Gupta Jun 02 '22 at 13:30
3

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.

Tom Deseyn
  • 1,735
  • 3
  • 17
  • 29
2

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
TamusJRoyce
  • 817
  • 1
  • 12
  • 25
  • Perfect. I see that you call `Dispose` on method that you register on GC. This should be rated higher on the top. – Jeson Martajaya May 17 '19 at 17:02
  • Note that HttpClient does resource pooling per base URL. So if you are hitting thousands of different websites in a list, your performance will degrade without cleaning up those individual sites. This exposes the ability to dispose each base-url. However, if you are only using one website, it might only be for academic reasons to call dispose. – TamusJRoyce May 18 '19 at 03:30
1

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

alastairtree
  • 3,960
  • 32
  • 49
0

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?

Dave Black
  • 7,305
  • 2
  • 52
  • 41
-2

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;
abatishchev
  • 98,240
  • 88
  • 296
  • 433
yayadavid
  • 454
  • 4
  • 13
  • 3
    Something to watch out for when doing this (and other similar schemes): "[Any instance members are not guaranteed to be thread safe.](http://msdn.microsoft.com/en-us/library/system.net.http.httpclient)" – tne Sep 24 '14 at 11:56
  • 2
    Whether this answer is correct or not should totally be dependent on what the application is that you want to use HttpClient from. If you have a web application and create a singleton HttpClient that all web requests would then share from you're potentially gonna get a lot of connection exceptions (depending on how popular your website is! :-)). (See David Faivre's answer) – bytedev Jan 07 '16 at 13:55