对 .NET Core 上的 gRPC 进行故障排除Troubleshoot gRPC on .NET Core

本文内容

作者:James Newton-King

本文档讨论了在 .NET 上开发 gRPC 应用时经常遇到的问题。

客户端和服务 SSL/TLS 配置不匹配Mismatch between client and service SSL/TLS configuration

默认情况下,gRPC 模板和示例使用传输层安全性 (TLS) 来保护 gRPC 服务。gRPC 客户端需要使用安全连接才能成功调用受保护的 gRPC 服务。

可在应用启动时验证 ASP.NET Core gRPC 服务是否正在使用 TLS。该服务将在 HTTPS 终结点上侦听:

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

.NET Core 客户端必须在服务器地址中使用 https 才能使用安全连接进行调用:

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

所有 gRPC 客户端实现都支持 TLS。其他语言的 gRPC 客户端通常需要配置有 SslCredentials 的通道。SslCredentials 指定客户端将使用的证书,必须使用该证书,而不是使用不安全凭据。有关配置不同 gRPC 客户端实现以使用 TLS 的示例,请参阅 gRPC 身份验证

使用不受信任/无效证书调用 gRPC 服务Call a gRPC service with an untrusted/invalid certificate

.NET gRPC 客户端要求服务具有受信任的证书。在没有受信任证书的情况下调用 gRPC 服务时,将返回以下错误消息:


未经处理的异常。 System.Net.Http.HttpRequestException:无法建立 SSL 连接,请查看内部异常。
—-> System.Security.Authentication.AuthenticationException:根据验证过程,远程证书无效。


如果在本地测试应用且 ASP.NET Core HTTPS 开发证书不受信任,则可能会显示此错误。有关解决此问题的说明,请参阅在 Windows 和 macOS 上信任 ASP.NET Core HTTPS 开发证书

如果要在另一台计算机上调用 gRPC 服务且无法信任该证书,则可以将 gRPC 客户端配置为忽略无效的证书。下面的代码使用 HttpClientHandler.ServerCertificateCustomValidationCallback 来允许在没有受信任证书的情况下进行调用:

  1. var httpClientHandler = new HttpClientHandler();
  2. // Return `true` to allow certificates that are untrusted/invalid
  3. httpClientHandler.ServerCertificateCustomValidationCallback =
  4. HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
  5. var httpClient = new HttpClient(httpClientHandler);
  6. var channel = GrpcChannel.ForAddress("https://localhost:5001",
  7. new GrpcChannelOptions { HttpClient = httpClient });
  8. var client = new Greet.GreeterClient(channel);

警告

不受信任的证书只应在应用开发过程中使用。生产应用应始终使用有效的证书。

使用 .NET Core 客户端调用不安全的 gRPC 服务Call insecure gRPC services with .NET Core client

若要使用 .NET Core 客户端调用不安全的 gRPC 服务,需要其他配置。gRPC 客户端必须将 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport 开关设置为 true 并在服务器地址中使用 http

  1. // This switch must be set before creating the GrpcChannel/HttpClient.
  2. AppContext.SetSwitch(
  3. "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
  4. // The port number(5000) must match the port of the gRPC server.
  5. var channel = GrpcChannel.ForAddress("http://localhost:5000");
  6. var client = new Greet.GreeterClient(channel);

无法在 macOS 上启动 ASP.NET Core gRPC 应用Unable to start ASP.NET Core gRPC app on macOS

Kestrel 不支持 macOS 和更早的 Windows 版本(如 Windows 7)上的带有 TLS 的 HTTP/2。默认情况下,ASP.NET Core gRPC 模板和示例使用 TLS。尝试启动 gRPC 服务器时,你将看到以下错误消息:


无法绑定到 IPv4 环回接口上的 https://localhost:5001 :“由于缺少 ALPN 支持,macOS 不支持使用 TLS 的 HTTP/2。”。


若要解决此问题,请将 Kestrel 和 gRPC 客户端配置为使用不带有 TLS 的 HTTP/2 。应仅在开发过程中执行此操作。如果不使用 TLS,将会在不加密的情况下发送 gRPC 消息。

Kestrel 必须在 Program.cs 中配置不带有 TLS 的 HTTP/2 终结点 :

  1. public static IHostBuilder CreateHostBuilder(string[] args) =>
  2. Host.CreateDefaultBuilder(args)
  3. .ConfigureWebHostDefaults(webBuilder =>
  4. {
  5. webBuilder.ConfigureKestrel(options =>
  6. {
  7. // Setup a HTTP/2 endpoint without TLS.
  8. options.ListenLocalhost(5000, o => o.Protocols =
  9. HttpProtocols.Http2);
  10. });
  11. webBuilder.UseStartup<Startup>();
  12. });

如果在未带有 TLS 的情况下配置了 HTTP/2 终结点,则终结点的 ListenOptions.Protocols 必须设置为 HttpProtocols.Http2无法使用 HttpProtocols.Http1AndHttp2,因为需要使用 TLS 来协商 HTTP/2。如果未带有 TLS,则与终结点的所有连接均默认为 HTTP/1.1,且 gRPC 调用会失败。

还必须将 gRPC 客户端配置为不使用 TLS。有关详细信息,请参阅使用 .NET Core 客户端调用不安全的 gRPC 服务

警告

应仅在应用开发过程中使用不带有 TLS 的 HTTP/2。生产应用应始终使用传输安全性。有关详细信息,请参阅适用于 ASP.NET Core 的 gRPC 的安全注意事项

gRPC C# 资产不是从 .proto 文件生成的代码gRPC C# assets are not code generated from .proto files

具体客户端和服务基类的 gRPC 代码生成需要从项目引用 protobuf 文件和工具。必须包括:

有关生成 gRPC C# 资产的详细信息,请参阅 使用 C# 的 gRPC 服务

默认情况下,<Protobuf> 引用将生成具体的客户端和服务基类。可使用引用元素的 GrpcServices 特性来限制 C# 资产生成。有效 GrpcServices 选项如下:

  • Both(如果不存在,则为默认值)
  • Server
  • Client
  • None

托管 gRPC 服务的 ASP.NET Core web 应用仅需要已生成的服务基类:

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

发出 gRPC 调用的 gRPC 客户端应用仅需要已生成的具体客户端:

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

WPF 项目无法从 .proto 文件生成 gRPC C# 资产WPF projects unable to generate gRPC C# assets from .proto files

WPF 项目存在一个已知问题,其阻止 gRPC 代码生成正常运行。在 WPF 项目中通过引用 Grpc.Tools 和 .proto 文件生成的任何 gRPC 类型在使用时都将创建编译错误 :


错误 CS0246:找不到类型名称或命名空间名称 ’MyGrpcServices’ (是否缺少 using 指令或程序集引用?)


可以通过以下方式解决此问题:

  • 创建新的 .NET Core 类库项目。
  • 在新项目中,添加引用以从 *.proto 文件启用 C# 代码生成
    • 将包引用添加到 Grpc.Tools 包。
    • 将 *.proto 文件添加到 <Protobuf> 项目组。
  • 在 WPF 应用程序中,添加对新项目的引用。
    WPF 应用程序可以使用来自新类库项目的 gRPC 生成的类型。

Azure 应用服务不支持 gRPCgRPC not supported on Azure App Service

警告

Azure 应用服务或 IIS 当前不支持 ASP.NET Core gRPCHttp.Sys 的 HTTP/2 实现不支持 gRPC 依赖的 HTTP 响应尾随标头。有关详细信息,请参阅此 GitHub 问题