Troubleshoot gRPC on .NET Core

By James Newton-King

This document discusses commonly encountered problems when developing gRPC apps on .NET.

Mismatch between client and service SSL/TLS configuration

The gRPC template and samples use Transport Layer Security (TLS) to secure gRPC services by default. gRPC clients need to use a secure connection to call secured gRPC services successfully.

You can verify the ASP.NET Core gRPC service is using TLS in the logs written on app start. The service will be listening on an HTTPS endpoint:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

The .NET Core client must use https in the server address to make calls with a secured connection:

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

All gRPC client implementations support TLS. gRPC clients from other languages typically require the channel configured with SslCredentials. SslCredentials specifies the certificate that the client will use, and it must be used instead of insecure credentials. For examples of configuring the different gRPC client implementations to use TLS, see gRPC Authentication.

Call a gRPC service with an untrusted/invalid certificate

The .NET gRPC client requires the service to have a trusted certificate. The following error message is returned when calling a gRPC service without a trusted certificate:

Unhandled exception. System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

You may see this error if you are testing your app locally and the ASP.NET Core HTTPS development certificate is not trusted. For instructions to fix this issue, see Trust the ASP.NET Core HTTPS development certificate on Windows and macOS.

If you are calling a gRPC service on another machine and are unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate. The following code uses HttpClientHandler.ServerCertificateCustomValidationCallback to allow calls without a trusted certificate:

var httpClientHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpClientHandler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(httpClientHandler);

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greet.GreeterClient(channel);

Warning

Untrusted certificates should only be used during app development. Production apps should always use valid certificates.

Call insecure gRPC services with .NET Core client

Additional configuration is required to call insecure gRPC services with the .NET Core client. The gRPC client must set the System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport switch to true and use http in the server address:

// This switch must be set before creating the GrpcChannel/HttpClient.
AppContext.SetSwitch(
    "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

// The port number(5000) must match the port of the gRPC server.
var channel = GrpcChannel.ForAddress("http://localhost:5000");
var client = new Greet.GreeterClient(channel);

Unable to start ASP.NET Core gRPC app on macOS

Kestrel doesn't support HTTP/2 with TLS on macOS and older Windows versions such as Windows 7. The ASP.NET Core gRPC template and samples use TLS by default. You'll see the following error message when you attempt to start the gRPC server:

Unable to bind to https://localhost:5001 on the IPv4 loopback interface: 'HTTP/2 over TLS is not supported on macOS due to missing ALPN support.'.

To work around this issue, configure Kestrel and the gRPC client to use HTTP/2 without TLS. You should only do this during development. Not using TLS will result in gRPC messages being sent without encryption.

Kestrel must configure an HTTP/2 endpoint without TLS in Program.cs:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                // Setup a HTTP/2 endpoint without TLS.
                options.ListenLocalhost(5000, o => o.Protocols = 
                    HttpProtocols.Http2);
            });
            webBuilder.UseStartup<Startup>();
        });

When an HTTP/2 endpoint is configured without TLS, the endpoint's ListenOptions.Protocols must be set to HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 can't be used because TLS is required to negotiate HTTP/2. Without TLS, all connections to the endpoint default to HTTP/1.1, and gRPC calls fail.

The gRPC client must also be configured to not use TLS. For more information, see Call insecure gRPC services with .NET Core client.

Warning

HTTP/2 without TLS should only be used during app development. Production apps should always use transport security. For more information, see Security considerations in gRPC for ASP.NET Core.

gRPC C# assets are not code generated from .proto files

gRPC code generation of concrete clients and service base classes requires protobuf files and tooling to be referenced from a project. You must include:

  • .proto files you want to use in the <Protobuf> item group. Imported .proto files must be referenced by the project.
  • Package reference to the gRPC tooling package Grpc.Tools.

For more information on generating gRPC C# assets, see gRPC services with C#.

By default, a <Protobuf> reference generates a concrete client and a service base class. The reference element's GrpcServices attribute can be used to limit C# asset generation. Valid GrpcServices options are:

  • Both (default when not present)
  • Server
  • Client
  • None

An ASP.NET Core web app hosting gRPC services only needs the service base class generated:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

A gRPC client app making gRPC calls only needs the concrete client generated:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

WPF projects unable to generate gRPC C# assets from .proto files

WPF projects have a known issue that prevents gRPC code generation from working correctly. Any gRPC types generated in a WPF project by referencing Grpc.Tools and .proto files will create compilation errors when used:

error CS0246: The type or namespace name 'MyGrpcServices' could not be found (are you missing a using directive or an assembly reference?)

You can workaround this issue by:

  1. Create a new .NET Core class library project.
  2. In the new project, add references to enable C# code generation from *.proto files:
    • Add a package reference to Grpc.Tools package.
    • Add *.proto files to the <Protobuf> item group.
  3. In the WPF application, add a reference to the new project.

The WPF application can use the gRPC generated types from the new class library project.

gRPC not supported on Azure App Service

Warning

ASP.NET Core gRPC is not currently supported on Azure App Service or IIS. The HTTP/2 implementation of Http.Sys does not support HTTP response trailing headers which gRPC relies on. For more information, see this GitHub issue.