I'm trying to request data over HTTP 2.0. I'm using the HttpClient from .Net Core 2.2. I'm on Windows 10 but will run on Linux in production. The problem is that the version on the response seems to always be "1.1". What I am doing wrong?
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("GET"),
"https://duckduckgo.com/"
))
{
request.Version = new Version(2, 0);
var response = await client.SendAsync(request);
Console.WriteLine(response.Version);
}
}
Launch your browser from your Windows 10 or Windows Server 2016 machine and hit F12, (or go to Settings and enable F12 Developer Tools), and then switch to the Network tab. Browse to https://localhost and voila, you are on HTTP/2!
HTTP2 is much faster and more reliable than HTTP1. HTTP1 loads a single request for every TCP connection, while HTTP2 avoids network delay by using multiplexing. HTTP is a network delay sensitive protocol in the sense that if there is less network delay, then the page loads faster.
Browser Compatibility: HTTP/2 is compatible with almost all browsers and is backward compatible with previous protocol versions like HTTP/1.1. The standardization effort was supported by most client browsers including Chrome and Firefox with the condition that it should be used only over TLS.
Update - .NET Core 3.0
.NET Core 3.0 now supports HTTP/2. The following code will print 2.0
:
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, "https://http2.akamai.com/demo"){
Version = new Version(2, 0)
};
var x = await client.SendAsync(req);
var version = x.Version;
Console.WriteLine(version);
Original Answer
You can't use HTTP/2 with HttpClient in .NET Core 2.1 or 2.2, even if you explicitly set the version in the request. You'll have to explicitly configure .NET Core to use the old HttpClientHandler instance that came with .NET Core 2.0, either by setting an App Context switch with :
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
Or by setting the DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER
environment variable to 0
or false
.
The discussion in this Github issue shows that HTTP/2 support is planned for .NET Core 3.0. The 3.0 Preview 1 released at Microsoft Connect 2018 doesn't support HTTP/2 yet.
The HttpClientHandler used up to .NET Core 2.0 supported HTTP/2. The following code will return 2.0
in a project that targets Core 2.0 :
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, "https://http2.akamai.com/demo")
{
Version = new Version(2, 0)
};
var x = await client.SendAsync(req);
var version = x.Version;
Console.WriteLine(version);
Just make sure you thoroughly clean your project if you change the target runtime - delete bin
, obj
and all target files, or you may end up running with the wrong runtime as I did.
In 2.1 a new, far faster SocketsHttpClientHandler was added as a default. The new handler doesn't support HTTP/2 yet. The same code will return 1.1
as the protocol version.
If the app context switch is set before creating the HttpClient though, HTTP/2 is used. This code will return 2.0
. Interestingly, there's no need to specify the HTTP version. When HTTP/2 is available, the actual protocol version is negotiated. Both the Akamai URL and https://www.google.com
will use HTTP/2 even though the version wasn't specified:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, "https://http2.akamai.com/demo");
var x = await client.SendAsync(req);
var version = x.Version;
The switch and environment variable are explained in the official announcement for .NET Core 2.1 SDK Preview 2:
Sockets Performance and SocketsHttpHandler
We made major improvements to sockets in .NET Core 2.1. Sockets are the basis of both outgoing and incoming networking communication. The higher-level networking APIs in .NET Core 2.1, including HttpClient and Kestrel, are now based on .NET sockets. In earlier versions, these higher-level APIs were based on native networking implementations.
...
You can use one of the following mechanisms to configure a process to use the older HttpClientHandler:
From code, use the AppContext class:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
The AppContext switch can also be set by config file.
The same can be achieved via the environment variable DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER. To opt out, set the value to either false or 0.
The current suggested pattern is to register HttpClient
dependencies in the ConfigureServices
method: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests.
Here is an example of registering a default HttpClient
using a typed client and configuring it to use HTTP/2:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpClient<ExampleService>()
.ConfigureHttpClient((client) =>
{
client.DefaultRequestVersion = new Version(2, 0);
});
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With