HttpClient, HttpClientHandler, and WebRequestHandler Explained
In two previous blogs I describe how to use HttpClient as well as how to use the HttpMessageHandler pipeline. What we haven’t done explicitly is showing when and how to use HttpClient, HttpClientHandler, and WebRequestHandler. This is the purpose of this blog.
The first thing to remember is that HttpClient uses the HttpMessageHandler pipeline for sending and receiving requests. The default handler implementations (HttpClientHandler and WebRequestHandler) both sit on top of HttpWebRequest which has a lot of properties for controlling how to deal with requests and responses. However, in order to stay simple, HttpClient doesn’t expose all these properties up front – it would make it unwieldy and show a lot of things that are rarely used.
If you need to access these properties then there are two ways of doing it: use either HttpClientHandler or WebRequestHandler. Both are HttpMessageHandlers hooked in as part of the HttpMessageHandler pipeline. Below we will describe when and how to use these handlers, how they differ, as well as how to combine them with your own handlers.
You can find this code for this sample in the aspnet.codeplex.com code repository and there are instructions here for how to use the samples.
HttpClient
The default HttpClient is the simplest way in which you can start sending requests. A single HttpClient can be used to send as many HTTP requests as you want concurrently so in many scenarios you can just create one HttpClient and then use that for all your requests.
HttpClient has a few properties that are commonly used and which you can set up until the point where you start sending requests, namely:
Name | Description |
---|---|
BaseAddress | Gets or sets the base address of Uniform Resource Identifier (URI) of the Internet resource used when sending requests. |
DefaultRequestHeaders | Gets the headers which should be sent with each request. |
MaxResponseContentBufferSize | Gets or sets the maximum number of bytes to buffer when reading the response content. |
Timeout | Gets or sets the number of milliseconds to wait before the request times out. |
Here’s an example of how to create a simple HttpClient and issue a request while setting the timeout for all requests:
1: // Create an HttpClient and set the timeout for requests
2: HttpClient client = new HttpClient();
3: client.Timeout = TimeSpan.FromSeconds(10);
4:
5: // Issue a request
6: client.GetAsync(_address).ContinueWith(
7: getTask =>
8: {
9: if (getTask.IsCanceled)
10: {
11: Console.WriteLine("Request was canceled");
12: }
13: else if (getTask.IsFaulted)
14: {
15: Console.WriteLine("Request failed: {0}", getTask.Exception);
16: }
17: else
18: {
19: HttpResponseMessage response = getTask.Result;
20: Console.WriteLine("Request completed with status code {0}", response.StatusCode);
21: }
22: });
If you have additional handlers which you want to wire up as well then the simplest way is to use the HttpClientFactory class. Here’s an example wiring up 3 custom message handlers:
1: // Create an HttpClient and add message handlers for the client
2: HttpClient client = HttpClientFactory.Create(
3: new SampleHandler("Client A", 2),
4: new SampleHandler("Client B", 4),
5: new SampleHandler("Client C", 6));
HttpClientHandler
HttpClientHandler is an HttpMessageHandler with a common set of properties that works across most versions of the HttpWebRequest API. This is the default handler and so is what you get if you use the default constructor. However, in order to actually get access to the various properties (see below) you have to explicitly create it and then pass it to HttpClient.
Name | Description |
---|---|
AllowAutoRedirect | Gets or sets a value that indicates whether the handler should follow redirection responses. |
AutomaticDecompression | Gets or sets the type of decompression method used by the handler for automatic decompression of the HTTP content response. |
ClientCertificateOptions | Gets or sets the collection of security certificates that are associated with this handler. |
CookieContainer | Gets or sets the cookie container used to store server cookies by the handler. |
Credentials | Gets or sets authentication information used by this handler. |
MaxAutomaticRedirections | Gets or sets the maximum number of redirects that the handler follows. |
MaxRequestContentBufferSize | Gets or sets the maximum request content buffer size used by the handler. |
PreAuthenticate | Gets or sets a value that indicates whether the handler sends an Authorization header with the request. |
Proxy | Gets or sets proxy information used by the handler. |
SupportsAutomaticDecompression | Gets a value that indicates whether the handler supports automatic response content decompression. |
SupportsProxy | Gets a value that indicates whether the handler supports proxy settings. |
SupportsRedirectConfiguration | Gets a value that indicates whether the handler supports configuration settings for the AllowAutoRedirect and MaxAutomaticRedirections properties. |
UseCookies | Gets or sets a value that indicates whether the handler uses the CookieContainer property to store server cookies and uses these cookies when sending requests. |
UseDefaultCredentials | Gets or sets a value that controls whether default credentials are sent with requests by the handler. |
UseProxy | Gets or sets a value that indicates whether the handler uses a proxy for requests. |
Here’s an example of how to create an HttpClientHandler, set a property, and pass it to HttpClient:
1: // Create HttpClientHandler and set UseDefaultCredentials property
2: HttpClientHandler clientHandler = new HttpClientHandler();
3: clientHandler.UseDefaultCredentials = true;
4:
5: // Create an HttpClient using the HttpClientHandler
6: HttpClient client = new HttpClient(clientHandler);
Like above, you can combine your HttpClientHandler instance with other custom handlers, here’s what it looks like:
1: // Create HttpClientHandler and set UseDefaultCredentials property
2: HttpClientHandler clientHandler = new HttpClientHandler();
3: clientHandler.UseDefaultCredentials = true;
4:
5: // Create an HttpClient and add message handlers for the client
6: HttpClient client = HttpClientFactory.Create(
7: clientHandler,
8: new SampleHandler("Client A", 2),
9: new SampleHandler("Client B", 4),
10: new SampleHandler("Client C", 6));
WebRequestHandler
WebRequestHandler derives from HttpClientHandler but adds properties that generally only are available on full .NET. The WebRequestHandler is not included in the System.Net.Http DLL but rather in System.Net.Http.WebRequest DLL so you have to explicitly include that as a reference in order to see it. Otherwise it won’t show up.
Name | Description |
---|---|
AllowPipelining | Gets or sets a value that indicates whether to pipeline the request to the Internet resource. |
AuthenticationLevel | Gets or sets a value indicating the level of authentication and impersonation used for this request. |
CachePolicy | Gets or sets the cache policy for this request. |
ClientCertificates | Gets or sets the collection of security certificates that are associated with this request. |
ContinueTimeout | Gets or sets the amount of time, in milliseconds, the application will wait for 100-continue from the server before uploading data. |
ImpersonationLevel | Gets or sets the impersonation level for the current request. |
MaxResponseHeadersLength | Gets or sets the maximum allowed length of the response headers. |
ReadWriteTimeout | Gets or sets a time-out in milliseconds when writing a request to or reading a response from a server. |
ServerCertificateValidationCallback | Gets or sets a callback for verifying the remote Secure Sockets Layer (SSL) certificate used for authentication. |
UnsafeAuthenticatedConnectionSharing | Gets or sets a value that indicates whether to allow high-speed NTLM-authenticated connection sharing. |
Here’s an example of how to create an WebRequestHandler, set a property, and pass it to HttpClient:
1: // Create WebRequestHandler and set UseDefaultCredentials and AllowPipelining (for HTTP) properties
2: WebRequestHandler webRequestHandler = new WebRequestHandler();
3: webRequestHandler.UseDefaultCredentials = true;
4: webRequestHandler.AllowPipelining = true;
5:
6: // Create an HttpClient using the WebRequestHandler
7: HttpClient client = new HttpClient(webRequestHandler);
Again, you can combine the WebRequestHandler with your own handlers as well – here’s what it looks like:
1: // Create WebRequestHandler and set UseDefaultCredentials and AllowPipelining (for HTTP) properties
2: WebRequestHandler webRequestHandler = new WebRequestHandler();
3: webRequestHandler.UseDefaultCredentials = true;
4: webRequestHandler.AllowPipelining = true;
5:
6: // Create an HttpClient and add message handlers for the client
7: HttpClient client = HttpClientFactory.Create(
8: webRequestHandler,
9: new SampleHandler("Client A", 2),
10: new SampleHandler("Client B", 4),
11: new SampleHandler("Client C", 6));
Have fun!
Henrik
Comments
Anonymous
August 07, 2012
Thanks for taking the time to discuss that, I really feel strongly about it and love learning more on this topic. http://janinepatterson.com/Anonymous
August 08, 2012
Hi Henrik, Can you show an example of how to pass in forms authentication credentials using the classes you described?Anonymous
August 10, 2012
Wouldn't it be more correct to say HttpClientHandler sits on top of HttpWebRequest rather than HttpClient. Arguably, HTTPClient has no dependency on HttpWebRequest. HttpClient could use a completely new HTTP engine if someone built it.Anonymous
August 10, 2012
Darrel, that's correct although the default ctor of HttpClient uses an HttpClientHandler. Let me think of a way to describe that. HenrikAnonymous
November 01, 2012
Much appreciated articles. Thank you.Anonymous
November 25, 2012
None to the sample code explicitly disposes of the client of response which was important when using WebClient. Could you confirm that this is no longer critical. Also is HttpClient thread-safe? Should I create a new instance for every request or can I safely make multiple calls through the same one? ThanksAnonymous
November 30, 2013
I have API which connects to other api instance ( hosted on different data centers) based on value selected it may connect datacenter 1 API or datacenter n API. Is HTTPClient is an option here ? How it maintains State because based on data center selection it talks to corresponding API. All data center API's talk to Main API . Right now I am using HTTPWebRequest. Exploring and understanding the power of HTTPClient. your input on this will be greatly appreciated. Thanks in advance.Anonymous
December 26, 2013
Hello Henrik, I've a web forms project which calls WCF rest services (reside in the same project) from code behind using HtttpClient. Recently we've added forms authentication to our project and when we hit the service using HttpClient, we're redirected to the login page. I tried to use the CookieContainer (from WebRequestHandler.CookieContainer) to pass all the cookies from the original request to the code behind to WCF via httpclient but no good. Can you please suggest if this is possible or what i'm doing wrong? Thanks~Anonymous
September 26, 2014
The comment has been removedAnonymous
June 05, 2015
ClientCertificateOptions in HttpClientHandler does not get or set the collection of security certificates that are associated with this request. Rather it is a toggle between "Automatic" and "Manual". Do you know if there is a way to set the SecurityCertificate from HttpClientHandler (rather than WebRequestHandler). I'm trying to set the certificate in a Universal App. I do see that I can do it if I switch to Microsoft.Web's HttpClient using HttpBaseProtocolFilter but I'd rather share code without a lot of #ifdefs