# ASP.NET Core and Http2, Http3, gRPC

This post is a quick lap around using http2 and http3 and gRPC endpoints with ASP.NET Core.

ASP.NET Core's Kestrel host on .NET 7 supports hosting endpoints with http1, http2 and http3 protocols. We can host gRPC endpoints with ASP.NET Core both using http2 and http3.

The two questions I would like to answer:

- can we host http2 without SSL?
- how to invoke an http2 endpoint without SSL?
- how http3 REST performance compares with gRPC over h2?

## HTTP

Endpoints with http1 and http2 protocols support connecting with and without SSL (TLS), http3 requires secure endpoints. While the http2 standard allows to send non-secure H2 requests, modern browsers typically do not allow this and fall back to http/1.1. In these cases, ASP.NET Core will return an error message *An HTTP/1.x request was sent to an HTTP/2 only endpoint.* in case the endpoint is http2 only.

To configure ASP.NET Core to use *only* http2 without TLS add the following json configuration to the *appsettings.json* file:

```json
"Kestrel": {
    "Endpoints": {
      "http": {
        "Protocols": "Http2",
        "Url": "http://localhost:5001"
      }
    }
  }
```

Alternatively configure the endpoint options during application startup. To do that, add the following snippet to *Program.cs*:

```csharp
builder.WebHost.UseKestrel(kestrelOptions =>
{
    kestrelOptions.ListenAnyIP(5001, listenOptions =>
    {
        listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http3;
    });
});
```

Finally, remove https redirection in the http pipeline:

```csharp
app.UseHttpsRedirection();
```

To use *only* http3 without TLS add the following json configuration to the *appsettings.json* file.

```json
"Kestrel": {
    "Endpoints": {
      "http": {
        "Protocols": "Http3",
        "Url": "https://localhost:5001"
      }
    }
  }
```

## HttpClient

To make http2 and http3 requests with `HttpClient` set the `DefaultVersionPolicy` and `DefaultRequestVersion` accordingly, then use one of the `GetAsync`, `PutAsync`, `PostAsync`, etc. methods fire the HTTP request.

```csharp
HttpClient client = new HttpClient();
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;
client.DefaultRequestVersion = System.Net.HttpVersion.Version30;
var result = await client.GetAsync("https://localhost:5001/person/1", HttpCompletionOption.ResponseHeadersRead);
```

However, when using the `SendAsync` method with an instance of `HttpRequestMessage` make sure to set the `Version` and `VersionPolicy` properties on the request message itself:

```csharp
await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://localhost:5001/person/1") { Version = HttpVersion.Version30, VersionPolicy = HttpVersionPolicy.RequestVersionExact }, HttpCompletionOption.ResponseHeadersRead);
```

Without setting the values, the `DefaultVersionPolicy` and `DefaultRequestVersion` values set on the `HttpClient` will be overwritten by the defaults of `HttpRequestMessage`.

## gRPC

A http3 request-response body is typically a UTF-8 encoded json payload. gRPC uses [Protocol Buffers](https://github.com/protocolbuffers/protobuf) data format which is significantly more efficient. I was curious how much is "more efficient" it is. As this depends on the application and endpoint in question, I set up a sample request response pair, and implemented an endpoint in REST (with H3) and gRPC (with H2). For brevity, the request-response pair is omitted from this post, but it was a typical DTO representing a *Person* and its *Address*.

Implemented two client applications to compare the performance: one using `HttpClient` and one with gRPC client. Both, firing 10000 requests from 100 parallel threads. In my tests the gRPC service yields ~30% better performance to the REST endpoint. Most of the gains come from the efficiency of encoding and decoding proto messages. To reveal how efficient a proto message is, I compared the size of the response messages: the sample message was 171 bytes with gRPC, and 381 bytes with the json encoding. These number are completely specific to the sample data processed and by these endpoints.

I ask the kind reader not to generalize from these results. To make a well-informed decision from performance point of view over one or the other technology, care measurements must be made that are tailored to the characteristics of the application in question.