I have been tasked with maintaining an C# web service that pretty much boils down to the following code that is used in conjunction with IIS 8:
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// here we process the request and return it after fetching some data
}
}
Now I need to create another web service, which in turn will request another web service for fetching data. What I've gathered is that the HttpClient() in C# is the new shiny, however finding out how to implement it in my case is not so easy (or if that would be a good solution).
My solution would something like
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// make sure that the incoming request is valid
HttpClient client = new HttpClient();
// do stuff with ^client and request the other service
[..]
// return the data from the response from ^client to the first request
}
}
Am I on the right track or would this be a catastrophe? I would gladly take tips or pointers to relevant documentation.
There are two issues with your approach.
First, as others have said, HttpClient must not be created for each request, as this would result in your server creating one new TCP connection for each request and not dispose it from your connection pool until they reach their MaxIdleTimeout.
This is because each instance of HttpClient (or rather, each instance of HttpClientHandler) creates a unique ConnectionGroup within the ConnectionPool, so two HttpClient (created in such a way) will not share the same connections.
You can quite easily exhaust your ports (because connections are kept alive for quite some time), and even without that, you'll have all the performance issues you might find when deactivating keepalive (typically when connecting on a HTTPs server).
As for a solution, you might add a private readonly HttpClient field in your handler that you would initialize as you've done in your code (I believe HttpHandlers are instanciated once by IIS, not per-request, as long as it says it's reusable). (Edit: note that HttpClient instances are thread-safe).
The other problem you'll find is that IHttpHandler are synchronous by design. This means you'll have to return task.Result in your code. This will block the current thread (let's call it A), and all subsequent processing of the outbound request (sending the body of the request, reading the header of the response and reading the body of the response) will spawn use a thread from the thread pool to process this (let's call them B, C, and D, though they can all be the same thread since no step overlap in time).
But in Asp.net, you cannot safely do that. When your main thread A is processing an Asp.net inbound request, it will, simply put, lock the current context. And when threads B, C and D will be spawn to process the outbound request, they too, will try to acquire and lock the current context. But because your main thread A is blocked, the context has not been released. This will effectively result in deadlocks (A locks the context and wait for B/C/D, B/C/D wait for the context).
To work around this, I would advise you to use instead a IHttpAsyncHandler. Async process are not made to be used synchronous, and HttpClient can only be used in an async way.
However, this might prove much more challenging for a first usage scenario. It would be much more easier to use a HttpClient from the context of a WebApi server. However, without any knowledge as to why you have to use a HttpHandler, I do not know if this would be in the realm of acceptable answers.
There are other way to run asynchronous tasks and wait synchronously for them (such as changing temporary the CurrentContext), but they're all very dangerous.
As a side note, HttpClient is the new shiny thing, and works quite well with other new shiny things such as "all-the-way async infrastructure". But trying to use it HttpClient in an older infrastructure is not as easy.
Better solution example:
public class YourApp
{
private static HttpClient Client = new HttpClient();
public static void Main(string[] args)
{
Console.WriteLine("Requests about to start!");
for(int i = 0; i < 5; i++)
{
var result = Client.GetAsync("http://www.stackoverflow.com").Result;
Console.WriteLine(result);
}
Console.WriteLine("Requests are finished!");
Console.ReadLine();
}
}
Related
I have the following endpoint:
[HttpPost("Submit")]
public String post()
{
_ = _service.SubmitMetric("test", MetricType.Count, 60, 1);
return "done";
}
And the service implementation:
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return httpClient.PostAsync(<params>);
}
}
When I run the code and call the endpoint, the HTTP POST is not triggered. However, if I change my code to:
public async Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return await httpClient.PostAsync(<params>);
}
}
the POST is submitted as expected. Why is that happening, and what can I do if I don't really care about the HTTP response? I just want to submit it and continue my flow. Shouldn't I be able to use it without awaiting the result? For example:
public void SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
httpClient.PostAsync(<params>);
}
}
There are two problems with this code. If either was fixed, there would be no problem:
The HttpClient is used incorrectly. An HttpClient object is thread-safe and meant to be reused, not disposed. Disposing it like this leaks sockets and can result in application crashes or worse, instability. An HttpClient resolves the URL's Host to a socket and caches that socket. The OS also caches opened sockets because opening them is expensive. They're kept alive for a while even if an application closes them because some packets may still be in transit
By not awaiting PostAsync execution exits the using block and the HttpClient instance is disposed before the request had a chance to even start.
In any case, making a POST doesn't take long so there's no need to make the method fire-and-forget. Besides, few applications are OK with losing metrics, especially when things go wrong. That's when metrics are most useful.
Which is why ASP.NET Core 6 adds built-in support for OpenTelemetry tracing and metrics. More on that at the end, but the supporting packages can be used in ASP.NET Framework as well. You may be able to replace your current service with a built-in one.
Use await - not enough
One way to fix this is to use await but that doesn't solve the HttpClient usage problem.
public async Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return await httpClient.PostAsync(<params>);
}
}
At the very least the HttpClient should be stored in a field. Once that's done though, there's no longer any reason to await, provided the service itself is still around :
HttpClient httpClient = new HttpClient();
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
return httpClient.PostAsync(<params>);
}
Long lived services
Which brings us to keeping the service around. In ASP.NET and ASP.NET Core each request is served by a separate thread, in a new instance of the Controller class. The request itself is used as a GC scope so anything created during a request is disposed once this concludes, including the HttpClient instance.
To keep the Metrics service around we need to either register it as Singleton in ASP.NET Core's DI, make it a BackgroundService or ensure it's a singleton in ASP.NET Framework. We could make the field static, but that leads to the next issue.
Proper HttpClient usage
HttpClient can still cause problems if used as a singleton. The HttpClient caches sockets to specific machines. If that machine goes away, the HttpClient will still try to communicate with it causing errors. This can happen easily when the remote services uses a load balancer or fails over to a new server. To fix this, the HttpClient instance or rather the sockets, need to be recycled periodically.
That's the job of the HttpClientFactory. This class caches and recycles SocketClientHandler instances, the classes that do the actual work in an HttpClient. These are recycled periodically, eg every 10 minutes. When asked for a new HttpClient instance, it creates a new instance wrapping one of the already available handlers.
When you use services.AddHttpClient in ASP.NET Core you're actually configuring an HttpClientFactory. When you add an HttpClient dependency in a controller, the instance will be created by the configured HttpClientFactory.
This means that the following action would work properly :
HttpClient _client;
public MyController(HttpClient client)
{
_client=client;
}
[HttpPost("Submit")]
public String post()
{
await _client.PostAsync(<params>);
return "done";
}
A scoped service with an HttpClient dependency would also work:
MyService _service;
public MyController(MyService service)
{
_service=service;
}
HttpPost("Submit")]
public String post()
{
await _service.SubmitMetric("test", MetricType.Count, 60, 1);
return "done";
}
where MyService is :
class MyService
{
HttpClient _client;
public MyService(HttpClient client)
{
_client=client;
}
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
return httpClient.PostAsync(<params>);
}
}
In this case there's no real need to await inside SubmitMetric, that's taken care of by the action.
Using the built-in OpenTelemetry tracing and metrics
ASP.NET Core 6, the upcoming Long-Term-Support version, adds native support for the OpenTelemetry standard for logging, tracing and metrics. This allows using a standard API to push metrics to a lot of different observability applications like Prometheus, Jaeger, Zipking, Elastic and Splunk.
Instead of rolling one's own metrics infrastructure it's better to use the standard API. OpenTelemetry for .NET supports this in ASP.NET Framework 4.6 and later. ASP.NET Core 5 and later are instrumented to publish metrics and tracing to OpenTelemetry providers through the built-in System.Diagnostics namespace and the Activity class.
In fact, Controller is already instrumented so you could get rid of the metrics service, adding any Tags and Baggage to the request's current activity:
[HttpPost("Submit")]
public String post()
{
Activity.Current?.AddTag("test");
...
return "done";
}
Metrics were added in ASP.NET Core 6 Preview 5:
Meter meter = new Meter("my.library.meter.name", "v1.0");
Counter<int> _counter;
public MyController(...)
{
_counter = meter.CreateCounter<int>("Requests");
}
[HttpPost("Submit")]
public String post()
{
counter.Add(60, KeyValuePair.Create<string, object>("request", "test"));
return "done";
}
Don't do it. Await for it even though you discard the result.
Fire and forget is an anti pattern and the context that you are performing the request can be invalidated/killed before the request could be completed, terminating the connection. Just await it, and don't do anything with the result.
httpClient will be disposed while the POST operation is running, probably resulting in killing the socket. If you use await, the object will remain inside the using clause while the operation is running, and it won't be terminated before it finishes.
Note that in your current implementation, you're creating a new connection on each API request, which might eventually lead to socket exhaustion. A better approach would be injecting IHttpClientFactory, which manage the lifetime of network connections for you, and reuses connections from the pool:
public class MyService
{
private readonly IHttpClientFactory _httpClient;
public MyService(IHttpClientFactory httpClient)
{
_httpClient = httpClient;
}
public async Task<HttpResponseMessage> SubmitMetric(/*<params>*/)
{
var httpClient = _httpClient.CreateClient();
return await httpClient.PostAsync(/*<params>*/);
}
}
Note: You need to add services.AddHttpClient() in ConfigureServices in your Startup.cs to enable injection.
I need to create an REST API that connect to a third party SOAP API. The third party API events are sent by callback to an URL I provide.
The typical steps my API go through is it starts a session with the third party by providing an ID and an callback URL. The third party can now send new events to my API through this URL when, for example, a new participant connects. Now sometimes i need to request specific info, like the list of participants for a given session(ID), and wait for the event containing the info.
Note that there may be multiple open sessions at the same time.
An example of what I need:
private string url = "http://myapi/callback";
[HttpGet]
[Route("createSession")]
public async Task<string> CreateSession()
{
var id = Guid.NewGuid().ToString();
var result = await ExternAPI.CreateSession(id, this.url);
return result; //contains the id
}
[HttpGet]
[Route("endSession")]
public async Task<string> EndSession([FromUri] string id)
{
var result = await ExternAPI.EndSession(id);
return result;
}
[HttpGet]
[Route("partipants")]
public async Task<string> Partipants([FromUri] string id)
{
ExternAPI.participants(id); // The results of this method will be sent to the callback function
results = // Wait for the results for this id
return results;
}
[HttpPost]
[Route("callback")]
public void Callback(body)
{
// notify waiting function and pass body
}
I came up with a solution using ReactiveX but I'm not really sure about its reliability in production. What I have in mind is to create a subject that never terminate and handle all the events but it is not a usual lifetime for a subject, what happens on error ? And I don't think I did it the "RX-way" (state concerns).
Here it is (you will need System.Reactive to run this code):
class Data
{
public int id;
public string value;
}
class Program
{
private static Subject<Data> sub;
static void Main(string[] args)
{
sub = new Subject<Data>();
Task.Run(async () => {
int id = 1;
ExternAPI(CallBackHook, id);
Data result = await sub.Where(data => data.id == id).FirstAsync();
Console.WriteLine("{0}", result.value);
});
Console.ReadLine();
}
static void CallBackHook(Data data)
{
sub.OnNext(data);
}
static String ExternAPI(Action<Data> callback, int id)
{
// Third-party API, access via SOAP. callback is normally an url (string)
Task.Run(() =>
{
Thread.Sleep(1000);
callback(new Data { id = id, value = "test" });
});
return "success";
}
}
An other way will be a dictionary of subjects, one for each session, so I could manage their lifetimes.
it is not a usual lifetime for a subject
what happens on error?
And I don't think I did it the "RX-way"
Yes, these are all perfectly valid concerns with this kind of approach. Personally, I don't much mind the last one, because even though Subjects are frowned-upon, many times they're just plain easier to use than the proper Rx way. With the learning curve of Rx what it is, I tend to optimize for developer maintainability, so I do "cheat" and use Subjects unless the alternative is equally understandable.
Regarding lifetime and errors, the solutions there depend on how you want your application to behave.
For lifetime, it looks like currently you have a WebAPI resource (the SOAP connection) requiring an explicit disconnect call from your client; this raises some red flags. At the very least, you'd want some kind of timeout there where that resource is disposed even if endSession is never called. Otherwise, it'll be all too easy to end up with dangling resources.
Also for errors, you'll need to decide the appropriate approach. You could "cache" the error and report it to each call that tries to use that resource, and "clear" the error when endSession is called. Or, if it's more appropriate, you could let an error take down your ASP.NET process. (ASP.NET will restart a new one for you).
To delay an API until you get some other event, use TaskCompletionSource<T>. When starting the SOAP call (e.g., ExternAPI.participants), you should create a new TCS<T>. The API call should then await the TaskCompletionSource<T>.Task. When the SOAP service responds with an event, it should take that TaskCompletionSource<T> and complete it. Points of note:
If you have multiple SOAP calls that are expecting responses over the same event, you'll need a collection of TaskCompletionSource<T> instances, along with some kind of message-identifier to match up which events are for which calls.
Be sure to watch your thread safety. Incoming SOAP events are most likely arriving on the thread pool, with (possibly multiple) API requests on other thread pool threads. TaskCompletionSource<T> itself is threadsafe, but you'd need to make your collection threadsafe as well.
You may want to write a Task-based wrapper for your SOAP service first (handling all the TaskCompletionSource<T> stuff), and then consume that from your WebAPI.
As a very broad alternative, instead of bridging SOAP with WebAPI, I would consider bridging SOAP with SignalR. You may find that this is a more natural translation. Among other things, SignalR will give you client-connect and client-disconnect events (complete with built-in timeouts for clients). So that may solve your lifetime issues more naturally. You can use the same Task-based wrapper for your SOAP service as well, or just expose the SOAP events directly as SignalR messages.
After reading the posts below about recommended usage of HttpClient, I changed my code from instantiating HttpClient per request within a using block to a long-lived object.
Do HttpClient and HttpClientHandler have to be disposed?
What is the overhead of creating a new HttpClient per call in a WebAPI client?
My implementation is part of a low-level api, and would be to make requests from from different parts of the app running on different threads, so thread-safety and concurrency when making requests needs to be guaranteed as well.
I even went on to make it a singleton as below, so there is just one instance of HttpClient used throughout the app. (fourth version form John SKeet's article)
http://csharpindepth.com/Articles/General/Singleton.aspx
public sealed class MyHttpClient
{
private static readonly volatile HttpClient _myHttpClient = new HttpClient();
static MyHttpClient() {}
private MyHttpClient(){ }
public static HttpClient MyHttpClientObj
{
get
{
return _myHttpClient;
}
}
}
And below is an example of how this gets used
public IEnumerable<string> GetSomeData(string url, FormUrlEncodedContent bodyParameters)
{
try
{
//is it possible to configure timeout here instead, such that every request will have its one timeout duration?
var response = MyHttpClient.MyHttpClientObj.PostAsync(url, bodyParameters);
var result = response.Result;
if (!result.IsSuccessStatusCode)
{
//log and return null
}
var data = JsonConvert.DeserializeObject<List<string>>(result.Content.ReadAsStringAsync().Result);
return data;
}
catch (Exception ex)
{
//logging exceptions
}
}
When making requests via HttpClient, I've made sure to use only the therad-safe methods listed below, but when deserializing the response, result.Content.ReadAsStringAsync().Result is used. This is because the higher level calls don't support async responses yet.
https://msdn.microsoft.com/en-us/library/system.net.http.httpclient(v=vs.110).aspx#Anchor_5
However, I still have a few questions.
Is this approach Thread-safe and stable enough to not cause any memory leaks?
How can I configure the Timeout for every request?
Is it necessary to specify 'Connection: keep-alive' in DefaultHeaders?
How can I add a custom header/modify a default header for every request?
And finally, Are there any known performance issues/drawbacks in using HttpClient this way?
It's thread safe, and recommended.
Depending on your usage, the biggest thing may be to raise the connection limit to your desired level of concurrency:
ServicePointManager.DefaultConnectionLimit = 16;
Without this set, concurrent requests to a single host will sit in a queue until they can be issued. And they'll time out if they're not got to in time.
I'd also recommend using pipelining to improve performance:
new HttpClient(new WebRequestHandler() { AllowPipelining = true });
Yes, this approach is thread-safe, as you call a thread-safe methods and do not you any synchronization logic, so your client threads simply independent from each other.
You can use an overload with CancellationTokenSource, with calling it method CancelAfter, this approach is recommended by MSDN.
No, but if your connection do require some interaction between client and server, it is highly recommended approach for HTTP/1.1, it reduces the overhead to recreating the socket connection and some handshakes between participating sides.
You can use the Headers property of the FormUrlEncodedContent class, simply add a header you need to it.
The huge drawback for your solution is .Result call, as it blocks the current thread. You can try to refactor your approach with TaskCompletionSource usage so you could possibly use async methods internally. This will provide you a possibility for the threads to do something else rather than wait for result.
The biggest performance issue you will encounter using HttpClient in a highly concurrent environment is the number of concurrent connections to any given url is limited to 2 by default. You can increase this for all endpoints using ServicePointManager.DefaultConnectionLimit or get a specific ServicePoint using ServicePointManager.FindServicePoint and set ServicePoint.ConnectionLimit
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;
So I've decided to up the performance a bit in my WCF application, and attempt to cache Channels and the ChannelFactory. There's two questions I have about all of this that I need to clear up before I get started.
1) Should the ChannelFactory be implemented as a singleton?
2) I'm kind of unsure about how to cache/reuse individual channels. Do you have any examples of how to do this you can share?
It's probably important to note that my WCF service is being deployed as a stand alone application, with only one endpoint.
EDIT:
Thank you for the responses. I still have a few questions though...
1)I guess I'm confused as to where the caching should occur. I'm delivering a client API that uses this code to another department in our company. Does this caching occur on the client?
2)The client API will be used as part of a Silverlight application, does this change anything? In particular, what caching mechanisms are available in such a scenario?
3)I'm still not clear about the design of the GetChannelFactory method. If I have only one service, should only one ChannelFactory ever be created and cached?
I still haven't implemented any caching feature (because I'm utterly confused about how it should be done!), but here's what I have for the client proxy so far:
namespace MyCompany.MyProject.Proxies
{
static readonly ChannelFactory<IMyService> channelFactory =
new ChannelFactory<IMyService>("IMyService");
public Response DoSomething(Request request)
{
var channel = channelFactory.CreateChannel();
try
{
Response response = channel.DoSomethingWithService(request);
((ICommunicationObject)channel).Close();
return response;
}
catch(Exception exception)
{
((ICommenicationObject)channel).Abort();
}
}
}
Use the ChannelFactory to create an instance of the factory, then cache that instance. You can then create communicatino channels as needed/desired from the cached istance.
Do you have a need for multiple channel factories (i.e.., are there multiple services)? In my experience, that's where you'll see the biggest benefit in performance. Creating a channel is a fairly inexpensive task; it's setting everything up at the start that takes time.
I would not cache individual channels - I'd create them, use them for an operation, and then close them. If you cache them, they may time out and the channel will fault, then you'll have to abort it and create a new one anyway.
Not sure why you'd want to usea singleton to implement ChannelFactory, especially if you're going to create it and cache it, and there's only one endpoint.
I'll post some example code later when I have a bit more time.
UPDATE: Code Examples
Here is an example of how I implemented this for a project at work. I used ChannelFactory<T>, as the application I was developing is an n-tier app with several services, and more will be added. The goal was to have a simple way to create a client once per life of the application, and then create communication channels as needed. The basics of the idea are not mine (I got it from an article on the web), though I modified the implementation for my needs.
I have a static helper class in my application, and within that class I have a dictionary and a method to create communication channels from the channelf factory.
The dictionary is as follows (object is the value as it will contain different channel factories, one for each service). I put "Cache" in the example as sort of a placeholder - replace the syntax with whatever caching mechanism you're using.
public static Dictionary<string, object> OpenChannels
{
get
{
if (Cache["OpenChannels"] == null)
{
Cache["OpenChannels"] = new Dictionary<string, object>();
}
return (Dictionary<string, object>)Cache["OpenChannels"];
}
set
{
Cache["OpenChannels"] = value;
}
}
Next is a method to create a communication channel from the factory instance. The method checks to see if the factory exists first - if it does not, it creates it, puts it in the dictionary and then generates the channel. Otherwise it simply generates a channel from the cached instance of the factory.
public static T GetFactoryChannel<T>(string address)
{
string key = typeof(T.Name);
if (!OpenChannels.ContainsKey(key))
{
ChannelFactory<T> factory = new ChannelFactory<T>();
factory.Endpoint.Address = new EndpointAddress(new System.Uri(address));
factory.Endpoint.Binding = new BasicHttpBinding();
OpenChannels.Add(key, factory);
}
T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel();
((IClientChannel)channel).Open();
return channel;
}
I've stripped this example down some from what I use at work. There's a lot you can do in this method - you can handle multiple bindings, assign credentials for authentication, etc. Its pretty much your one stop shopping center for generating a client.
Finally, when I use it in the application, I generally create a channel, do my business, and close it (or abort it if need be). For example:
IMyServiceContract client;
try
{
client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress");
client.DoSomething();
// This is another helper method that will safely close the channel,
// handling any exceptions that may occurr trying to close.
// Shouldn't be any, but it doesn't hurt.
Helper.CloseChannel(client);
}
catch (Exception ex)
{
// Something went wrong; need to abort the channel
// I also do logging of some sort here
Helper.AbortChannel(client);
}
Hopefully the above examples will give you something to go on. I've been using something similar to this for about a year now in a production environment and it's worked very well. 99% of any problems we've encountered have usually been related to something outside the application (either external clients or data sources not under our direct control).
Let me know if anything isn't clear or you have further questions.
You could always just make your ChannelFactory static for each WCF Contract...
You should be aware that from .Net 3.5 the proxy objects are pooled for performance reasons by the channel factory. Calling the ICommunicationObject.Close() method actually returns the object to the pool in the hope it can be reused.
I would look at the profiler if you want to do some optimisation, if you can prevent just one IO call being made in your code it could far outweigh any optimisation you will make with the channel factory. Don't pick an area to optimise, use the profiler to find where you can target an optimisation. If you have an SQL database for instance, you will probably find some low hanging fruit in your queries that will get you orders of magnitude performance increases if these haven't already been optimised.
Creating the Channel costs the performance so much. actually , WCF already has the cache mechanism for the ChannelFactory if you use the ClientBase in the client instead of the pure ChannelFactory. But the cache will be expired if you make some anditional operations(Please google it for details if you want).
For the ErOx's issue i got another solution i think it is better. see below:
namespace ChannelFactoryCacheDemo
{
public static class ChannelFactoryInitiator
{
private static Hashtable channelFactories = new Hashtable();
public static ChannelFactory Initiate(string endpointName)
{
ChannelFactory channelFactory = null;
if (channelFactories.ContainsKey(endpointName))//already cached, get from the table
{
channelFactory = channelFactories[endpointName] as ChannelFactory;
}
else // not cached, create and cache then
{
channelFactory = new ChannelFactory(endpointName);
lock (channelFactories.SyncRoot)
{
channelFactories[endpointName] = channelFactory;
}
}
return channelFactory;
}
}
class AppWhereUseTheChannel
{
static void Main(string[] args)
{
ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint");
}
}
interface IMyContract { }
}
you can customize the logic and the parameters of the Initiate method yourself if you got another requirement. but this initiator class is not limited only one endpoint. it is powerful for all of the endpoint in your application. hopefully. it works well for you. BTW. this solution is not from me. i got this from a book.