Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make the .net HttpClient use http 2.0?

I have an asp.net web api hosted on IIS 10 (windows server 2016). When I make a GET request to this from a Microsoft Edge browser, I see that HTTP 2.0 is used in IIS logs

2015-09-20 21:57:59 100.76.48.17 GET /RestController/Native - 443 - 73.181.195.76 HTTP/2.0 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/42.0.2311.135+Safari/537.36+Edge/12.10240 - 200 0 0 7299

However, when a GET request is made through a .net 4.6 client as below,

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.GetAsync("RestController/Native");
    if (response.IsSuccessStatusCode)
    {
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    }
}

I see the following HTTP 1.1 log in the server logs

2015-09-20 20:57:41 100.76.48.17 GET /RestController/Native - 443 - 131.107.160.196 HTTP/1.1 - - 200 0 0 707

How can I make the .net client use HTTP/2.0 ?

like image 418
tcb Avatar asked Sep 20 '15 22:09

tcb


People also ask

Does HttpClient support HTTP2?

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.

Does .NET framework support HTTP2?

NET Framework 4.6. 0 & 4.6. 1 supports HTTP/2. HTTP/2 is a new version of HTTP protocol, faster than http 1.1.

Is http 2 backwards compatible?

HTTP/2 is backwards compatible, browsers that do not support HTTP/2 will fallback to using HTTP/1.1.

Is http 2 required?

Does HTTP/2 require encryption? No. After extensive discussion, the Working Group did not have consensus to require the use of encryption (e.g., TLS) for the new protocol.


3 Answers

1.Make sure you are on the latest version of Windows 10.

2.Install WinHttpHandler:

Install-Package System.Net.Http.WinHttpHandler 

3.Extend WinHttpHandler to add http2.0 support:

public class Http2CustomHandler : WinHttpHandler {     protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)     {         request.Version = new Version("2.0");         return base.SendAsync(request, cancellationToken);     } } 

4.Pass above handler to the HttpClient constructor

using (var httpClient = new HttpClient(new Http2CustomHandler())) {       // your custom code } 
like image 117
Shawinder Sekhon Avatar answered Oct 01 '22 13:10

Shawinder Sekhon


HttpClient does not support HTTP/2 yet. It will be available in the next release (code name KATANA). Here is the link to their source code for the next release.

Till then, you could implement your own HttpMessageHandler object that implements HTTP/2 and pass it to the HttpClient's constructor (you probably can use their source code from KATANA).

like image 42
Racil Hilan Avatar answered Oct 01 '22 14:10

Racil Hilan


In addition to WinHttpHandler (as described in Shawinder Sekhon's answer), .NET Core 3.0 includes HTTP/2 support in the default SocketsHttpHandler (#30740). Since HTTP/1.1 is still the default, either the default must be changed by setting HttpClient.DefaultRequestVersion, or Version must be changed on each request. The version can be set when the request message is created:

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.SendAsync(
        new HttpRequestMessage(HttpMethod.Get, "RestController/Native")
        {
            Version = HttpVersion.Version20,
        });
    if (response.IsSuccessStatusCode)
    {
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    }
}

Or by using a custom HttpMessageHandler, such as:

public class ForceHttp2Handler : DelegatingHandler
{
    public ForceHttp2Handler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    {
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version20;
        return base.SendAsync(request, cancellationToken);
    }
}

which can delegate to SocketsHttpHandler, WinHttpHandler, or any other HttpMessageHandler which supports HTTP/2:

using (var client = new HttpClient(new ForceHttp2Handler(new SocketsHttpHandler())))
{
    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.GetAsync("RestController/Native");
    if (response.IsSuccessStatusCode)
    {
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    }
}
like image 43
Kevinoid Avatar answered Oct 01 '22 12:10

Kevinoid