-->Inheritance
Definition
Provides a base class for sending HTTP requests and receiving HTTP responses from a resource identified by a URI.
Beware of the.NET HttpClient 01 November 2016 on C#,.NET, Performance, HTTP, REST Background. In the old days of.NET (pre 4.5) sending a HTTP request to a server could be accomplished by either using the WebClient or at a much lower level via the HttpWebRequest. On.Net platform we have HttpClient,WebClient and RestSharp client libraries.This link has nice explanation of available client libraries and their differences for sending http requests and receiving http responses.
HttpMessageInvokerHttpMessageInvokerHttpMessageInvokerHttpMessageInvoker
HttpClientHttpClientHttpClientHttpClientExamples
The preceding code example uses an
async Task Main()
entry point. That feature requires C# 7.1 or later.Remarks
The HttpClient class instance acts as a session to send HTTP requests. An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.
The HttpClient also acts as a base class for more specific HTTP clients. An example would be a FacebookHttpClient providing additional methods specific to a Facebook web service (a GetFriends method, for instance). Derived classes should not override the virtual methods on the class. Instead, use a constructor overload that accepts HttpMessageHandler to configure any pre- or post-request processing instead.
By default on .NET Framework and Mono, HttpWebRequest is used to send requests to the server. This behavior can be modified by specifying a different channel in one of the constructor overloads taking a HttpMessageHandler instance as parameter. If features like authentication or caching are required, WebRequestHandler can be used to configure settings and the instance can be passed to the constructor. The returned handler can be passed to one of the constructor overloads taking a HttpMessageHandler parameter.
If an app using HttpClient and related classes in the System.Net.Http namespace intends to download large amounts of data (50 megabytes or more), then the app should stream those downloads and not use the default buffering. If the default buffering is used the client memory usage will get very large, potentially resulting in substantially reduced performance.
The following methods are thread safe:
HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors. Below is an example using HttpClient correctly.
The HttpClient is a high-level API that wraps the lower-level functionality available on each platform where it runs.
On each platform, HttpClient tries to use the best available transport:
Host/Runtime | Backend |
---|---|
Windows/.NET Framework | HttpWebRequest |
Windows/Mono | HttpWebRequest |
Windows/UWP | Windows native WinHttpHandler (HTTP 2.0 capable) |
Windows/.NET Core 1.0-2.0 | Windows native WinHttpHandler (HTTP 2.0 capable) |
Android/Xamarin | Selected at build-time. Can either use HttpWebRequest or be configured to use Android's native HttpURLConnection |
iOS, tvOS, watchOS/Xamarin | Selected at build-time. Can either use HttpWebRequest or be configured to use Apple's NSUrlSession (HTTP 2.0 capable) |
macOS/Xamarin | Selected at build-time. Can either use HttpWebRequest or be configured to use Apple's NSUrlSession (HTTP 2.0 capable) |
macOS/Mono | HttpWebRequest |
macOS/.NET Core 1.0-2.0 | libcurl -based HTTP transport (HTTP 2.0 capable) |
Linux/Mono | HttpWebRequest |
Linux/.NET Core 1.0-2.0 | libcurl -based HTTP transport (HTTP 2.0 capable) |
.NET Core 2.1 and later | System.Net.Http.SocketsHttpHandler |
Users can also configure a specific transport for HttpClient by invoking the HttpClient constructor that takes an HttpMessageHandler.
HttpClient and .NET Core
Starting with .NET Core 2.1, the System.Net.Http.SocketsHttpHandler class instead of
HttpClientHandler
provides the implementation used by higher-level HTTP networking classes such as HttpClient
. The use of SocketsHttpHandler offers a number of advantages:- A significant performance improvement when compared with the previous implementation.
- The elimination of platform dependencies, which simplifies deployment and servicing. For example,
libcurl
is no longer a dependency on .NET Core for macOS and .NET Core for Linux. - Consistent behavior across all .NET platforms.
If this change is undesirable, you can configure your application to use the older System.Net.Http.HttpClientHandler instead in a number of ways:
- By calling the AppContext.SetSwitch method as follows:
- By defining the
System.Net.Http.UseSocketsHttpHandler
switch in the .netcore.runtimeconfig.json configuration file: - By defining an environment variable named
DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER
and setting it to eitherfalse
or 0.
Constructors
HttpClient()HttpClient()HttpClient()HttpClient() | Initializes a new instance of the HttpClient class. |
HttpClient(HttpMessageHandler)HttpClient(HttpMessageHandler)HttpClient(HttpMessageHandler)HttpClient(HttpMessageHandler) | Initializes a new instance of the HttpClient class with a specific handler. |
HttpClient(HttpMessageHandler, Boolean)HttpClient(HttpMessageHandler, Boolean)HttpClient(HttpMessageHandler, Boolean)HttpClient(HttpMessageHandler, Boolean) | Initializes a new instance of the HttpClient class with a specific handler. |
Properties
BaseAddressBaseAddressBaseAddressBaseAddress | Gets or sets the base address of Uniform Resource Identifier (URI) of the Internet resource used when sending requests. |
DefaultProxyDefaultProxyDefaultProxyDefaultProxy | |
DefaultRequestHeadersDefaultRequestHeadersDefaultRequestHeadersDefaultRequestHeaders | Gets the headers which should be sent with each request. |
DefaultRequestVersionDefaultRequestVersionDefaultRequestVersionDefaultRequestVersion | |
MaxResponseContentBufferSizeMaxResponseContentBufferSizeMaxResponseContentBufferSizeMaxResponseContentBufferSize | Gets or sets the maximum number of bytes to buffer when reading the response content. |
TimeoutTimeoutTimeoutTimeout | Gets or sets the timespan to wait before the request times out. |
Methods
CancelPendingRequests()CancelPendingRequests()CancelPendingRequests()CancelPendingRequests() | Cancel all pending requests on this instance. |
DeleteAsync(String)DeleteAsync(String)DeleteAsync(String)DeleteAsync(String) | Send a DELETE request to the specified Uri as an asynchronous operation. |
DeleteAsync(String, CancellationToken)DeleteAsync(String, CancellationToken)DeleteAsync(String, CancellationToken)DeleteAsync(String, CancellationToken) | Send a DELETE request to the specified Uri with a cancellation token as an asynchronous operation. |
DeleteAsync(Uri)DeleteAsync(Uri)DeleteAsync(Uri)DeleteAsync(Uri) | Send a DELETE request to the specified Uri as an asynchronous operation. |
DeleteAsync(Uri, CancellationToken)DeleteAsync(Uri, CancellationToken)DeleteAsync(Uri, CancellationToken)DeleteAsync(Uri, CancellationToken) | Send a DELETE request to the specified Uri with a cancellation token as an asynchronous operation. |
Dispose()Dispose()Dispose()Dispose() | Releases the unmanaged resources and disposes of the managed resources used by the HttpMessageInvoker. (Inherited from HttpMessageInvoker) |
Dispose(Boolean)Dispose(Boolean)Dispose(Boolean)Dispose(Boolean) | Releases the unmanaged resources used by the HttpClient and optionally disposes of the managed resources. |
Equals(Object)Equals(Object)Equals(Object)Equals(Object) | Determines whether the specified object is equal to the current object. (Inherited from Object) |
GetAsync(String)GetAsync(String)GetAsync(String)GetAsync(String) | Send a GET request to the specified Uri as an asynchronous operation. |
GetAsync(String, CancellationToken)GetAsync(String, CancellationToken)GetAsync(String, CancellationToken)GetAsync(String, CancellationToken) | Send a GET request to the specified Uri with a cancellation token as an asynchronous operation. |
GetAsync(String, HttpCompletionOption)GetAsync(String, HttpCompletionOption)GetAsync(String, HttpCompletionOption)GetAsync(String, HttpCompletionOption) | Send a GET request to the specified Uri with an HTTP completion option as an asynchronous operation. |
GetAsync(String, HttpCompletionOption, CancellationToken)GetAsync(String, HttpCompletionOption, CancellationToken)GetAsync(String, HttpCompletionOption, CancellationToken)GetAsync(String, HttpCompletionOption, CancellationToken) | Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation. |
GetAsync(Uri)GetAsync(Uri)GetAsync(Uri)GetAsync(Uri) | Send a GET request to the specified Uri as an asynchronous operation. |
GetAsync(Uri, CancellationToken)GetAsync(Uri, CancellationToken)GetAsync(Uri, CancellationToken)GetAsync(Uri, CancellationToken) | Send a GET request to the specified Uri with a cancellation token as an asynchronous operation. |
GetAsync(Uri, HttpCompletionOption)GetAsync(Uri, HttpCompletionOption)GetAsync(Uri, HttpCompletionOption)GetAsync(Uri, HttpCompletionOption) | Send a GET request to the specified Uri with an HTTP completion option as an asynchronous operation. |
GetAsync(Uri, HttpCompletionOption, CancellationToken)GetAsync(Uri, HttpCompletionOption, CancellationToken)GetAsync(Uri, HttpCompletionOption, CancellationToken)GetAsync(Uri, HttpCompletionOption, CancellationToken) | Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation. |
GetByteArrayAsync(String)GetByteArrayAsync(String)GetByteArrayAsync(String)GetByteArrayAsync(String) | Sends a GET request to the specified Uri and return the response body as a byte array in an asynchronous operation. |
GetByteArrayAsync(Uri)GetByteArrayAsync(Uri)GetByteArrayAsync(Uri)GetByteArrayAsync(Uri) | Send a GET request to the specified Uri and return the response body as a byte array in an asynchronous operation. |
GetHashCode()GetHashCode()GetHashCode()GetHashCode() | Serves as the default hash function. (Inherited from Object) |
GetStreamAsync(String)GetStreamAsync(String)GetStreamAsync(String)GetStreamAsync(String) | Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation. |
GetStreamAsync(Uri)GetStreamAsync(Uri)GetStreamAsync(Uri)GetStreamAsync(Uri) | Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation. |
GetStringAsync(String)GetStringAsync(String)GetStringAsync(String)GetStringAsync(String) | Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation. |
GetStringAsync(Uri)GetStringAsync(Uri)GetStringAsync(Uri)GetStringAsync(Uri) | Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation. |
GetType()GetType()GetType()GetType() | Gets the Type of the current instance. (Inherited from Object) |
MemberwiseClone()MemberwiseClone()MemberwiseClone()MemberwiseClone() | Creates a shallow copy of the current Object. (Inherited from Object) |
PatchAsync(String, HttpContent)PatchAsync(String, HttpContent)PatchAsync(String, HttpContent)PatchAsync(String, HttpContent) | Sends a PATCH request to a Uri designated as a string as an asynchronous operation. |
PatchAsync(String, HttpContent, CancellationToken)PatchAsync(String, HttpContent, CancellationToken)PatchAsync(String, HttpContent, CancellationToken)PatchAsync(String, HttpContent, CancellationToken) | Sends a PATCH request with a cancellation token to a Uri represented as a string as an asynchronous operation. |
PatchAsync(Uri, HttpContent)PatchAsync(Uri, HttpContent)PatchAsync(Uri, HttpContent)PatchAsync(Uri, HttpContent) | Sends a PATCH request as an asynchronous operation. |
PatchAsync(Uri, HttpContent, CancellationToken)PatchAsync(Uri, HttpContent, CancellationToken)PatchAsync(Uri, HttpContent, CancellationToken)PatchAsync(Uri, HttpContent, CancellationToken) | Sends a PATCH request with a cancellation token as an asynchronous operation. |
PostAsync(String, HttpContent)PostAsync(String, HttpContent)PostAsync(String, HttpContent)PostAsync(String, HttpContent) | Send a POST request to the specified Uri as an asynchronous operation. |
PostAsync(String, HttpContent, CancellationToken)PostAsync(String, HttpContent, CancellationToken)PostAsync(String, HttpContent, CancellationToken)PostAsync(String, HttpContent, CancellationToken) | Send a POST request with a cancellation token as an asynchronous operation. |
PostAsync(Uri, HttpContent)PostAsync(Uri, HttpContent)PostAsync(Uri, HttpContent)PostAsync(Uri, HttpContent) | Send a POST request to the specified Uri as an asynchronous operation. |
PostAsync(Uri, HttpContent, CancellationToken)PostAsync(Uri, HttpContent, CancellationToken)PostAsync(Uri, HttpContent, CancellationToken)PostAsync(Uri, HttpContent, CancellationToken) | Send a POST request with a cancellation token as an asynchronous operation. |
PutAsync(String, HttpContent)PutAsync(String, HttpContent)PutAsync(String, HttpContent)PutAsync(String, HttpContent) | Send a PUT request to the specified Uri as an asynchronous operation. |
PutAsync(String, HttpContent, CancellationToken)PutAsync(String, HttpContent, CancellationToken)PutAsync(String, HttpContent, CancellationToken)PutAsync(String, HttpContent, CancellationToken) | Send a PUT request with a cancellation token as an asynchronous operation. |
PutAsync(Uri, HttpContent)PutAsync(Uri, HttpContent)PutAsync(Uri, HttpContent)PutAsync(Uri, HttpContent) | Send a PUT request to the specified Uri as an asynchronous operation. |
PutAsync(Uri, HttpContent, CancellationToken)PutAsync(Uri, HttpContent, CancellationToken)PutAsync(Uri, HttpContent, CancellationToken)PutAsync(Uri, HttpContent, CancellationToken) | Send a PUT request with a cancellation token as an asynchronous operation. |
SendAsync(HttpRequestMessage)SendAsync(HttpRequestMessage)SendAsync(HttpRequestMessage)SendAsync(HttpRequestMessage) | Send an HTTP request as an asynchronous operation. |
SendAsync(HttpRequestMessage, CancellationToken)SendAsync(HttpRequestMessage, CancellationToken)SendAsync(HttpRequestMessage, CancellationToken)SendAsync(HttpRequestMessage, CancellationToken) | Send an HTTP request as an asynchronous operation. |
SendAsync(HttpRequestMessage, HttpCompletionOption)SendAsync(HttpRequestMessage, HttpCompletionOption)SendAsync(HttpRequestMessage, HttpCompletionOption)SendAsync(HttpRequestMessage, HttpCompletionOption) | Send an HTTP request as an asynchronous operation. |
SendAsync(HttpRequestMessage, HttpCompletionOption, CancellationToken)SendAsync(HttpRequestMessage, HttpCompletionOption, CancellationToken)SendAsync(HttpRequestMessage, HttpCompletionOption, CancellationToken)SendAsync(HttpRequestMessage, HttpCompletionOption, CancellationToken) | Send an HTTP request as an asynchronous operation. |
ToString()ToString()ToString()ToString() | Returns a string that represents the current object. (Inherited from Object) |
Applies to
See also
Our web app is running in .Net Framework 4.0. The UI calls controller methods through ajax calls.
We need to consume REST service from our vendor. I am evaluating the best way to call REST service in .Net 4.0. The REST service requires Basic Authentication Scheme and itcan return data in both XML and JSON. There is no requirement for uploading/downloading huge data and I don't see anything in future. I took a look at few open source code projects for REST consumption and didn't find any value in those to justify additional dependency in the project. Started to evaluate
WebClient
and HttpClient
. I downloaded HttpClient for .Net 4.0 from NuGet. I searched for differences between
WebClient
and HttpClient
and this site mentioned that single HttpClient can handle concurrent calls and it can reuse resolved DNS, cookie config and authentication. I am yet to see practical values that we may gain due to the differences.I did a quick performance test to find how
WebClient
(sync calls), HttpClient
(sync and async) perform. and here are the results:Using same
HttpClient
instance for all the requests (min - max)WebClient sync: 8 ms - 167 ms
HttpClient sync: 3 ms - 7228 ms
HttpClient async: 985 - 10405 ms
HttpClient sync: 3 ms - 7228 ms
HttpClient async: 985 - 10405 ms
Using a new
HttpClient
for each request (min - max)WebClient sync: 4 ms - 297 ms
HttpClient sync: 3 ms - 7953 ms
HttpClient async: 1027 - 10834 ms
HttpClient sync: 3 ms - 7953 ms
HttpClient async: 1027 - 10834 ms
Code
My Questions
- The REST calls return in 3-4s which is acceptable. Calls to RESTservice are initiated in controller methods which gets invoked fromajax calls. To begin with, the calls run in a different thread anddoesn't block UI. So, can I just stick with sync calls?
- The above code was run in my localbox. In prod setup, DNS and proxylookup will be involved. Is there any advantage of using
HttpClient
overWebClient
? - Is
HttpClient
concurrency better thanWebClient
? From the test results, I seeWebClient
sync calls perform better. - Will
HttpClient
be a better design choice if we upgrade to .Net 4.5? Performance is the key design factor.
21.1k1010 gold badges120120 silver badges167167 bronze badges
user3092913user3092913
3 Answers
I live in both the F# and Web API worlds.
There's a lot of good stuff happening with Web API, especially in the form of message handlers for security, etc.
I know mine is only one opinion, but I would only recommend use of
HttpClient
for any future work. Perhaps there's some way to leverage some of the other pieces coming out of System.Net.Http
without using that assembly directly, but I cannot imagine how that would work at this time.Speaking of comparing these two
- HttpClient is more closer to HTTP than WebClient.
- HttpClient was not meant to be a complete replacement of Web Client, since there are things like report progress, custom URI scheme and making FTP calls that WebClient provides — but HttpClient doesn’t.
If you’re using .NET 4.5, please do use the async goodness with HttpClient that Microsoft provides to the developers. HttpClient is very symmetrical to the server side brethren of the HTTP those are HttpRequest and HttpResponse.
Update: 5 Reasons to use new HttpClient API:
- Strongly typed headers.
- Shared Caches, cookies and credentials
- Access to cookies and shared cookies
- Control over caching and shared cache.
- Inject your code module into the ASP.NET pipeline. Cleaner and modular code.
Reference
C# 5.0 Joseph Albahari
(Channel9 — Video Build 2013)
KyleMit60.3k3838 gold badges261261 silver badges423423 bronze badges
Anant DabhiAnant Dabhi11.1k44 gold badges3030 silver badges5252 bronze badges
HttpClient is the newer of the APIs and it has the benefits of
- has a good async programming model
- being worked on by Henrik F Nielson who is basically one of the inventors of HTTP, and he designed the API so it is easy for you to follow the HTTP standard, e.g. generating standards-compliant headers
- is in the .Net framework 4.5, so it has some guaranteed level of support for the forseeable future
- also has the xcopyable/portable-framework version of the library if you want to use it on other platforms - .Net 4.0, Windows Phone etc.
If you are writing a web service which is making REST calls to other web services, you should want to be using an async programming model for all your REST calls, so that you don't hit thread starvation. You probably also want to use the newest C# compiler which has async/await support.
Note: It isn't more performant AFAIK. It's probably somewhat similarly performant if you create a fair test.
Firstly, I am not an authority on WebClient vs. HttpClient, specifically. Secondly, from your comments above, it seems to suggest that WebClient is Sync ONLY whereas HttpClient is both.
I did a quick performance test to find how WebClient (Sync calls), HttpClient (Sync and Async) perform. and here are the results.
I see that as a huge difference when thinking for future, i.e. long running processes, responsive GUI, etc. (add to the benefit you suggest by framework 4.5 - which in my actual experience is hugely faster on IIS)
Owen Blacker3,22722 gold badges2929 silver badges6666 bronze badges
Anthony HorneAnthony Horne2,12222 gold badges2020 silver badges4646 bronze badges