針對 .NET Core 上的 gRPC 進行疑難排解Troubleshoot gRPC on .NET Core

James 牛頓-王By James Newton-King

本檔討論在 .NET 上開發 gRPC 應用程式時經常遇到的問題。This document discusses commonly encountered problems when developing gRPC apps on .NET.

用戶端與服務 SSL/TLS 設定不相符Mismatch between client and service SSL/TLS configuration

GRPC 範本和範例預設會使用傳輸層安全性(TLS)來保護 gRPC 服務。The gRPC template and samples use Transport Layer Security (TLS) to secure gRPC services by default. gRPC 用戶端必須使用安全連線,才能順利呼叫受保護的 gRPC 服務。gRPC clients need to use a secure connection to call secured gRPC services successfully.

您可以確認 ASP.NET Core gRPC 服務在應用程式啟動時所寫入的記錄中使用 TLS。You can verify the ASP.NET Core gRPC service is using TLS in the logs written on app start. 服務將接聽 HTTPS 端點: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

.NET Core 用戶端必須使用伺服器位址中的 https,才能使用安全的連線進行呼叫: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);
}

所有 gRPC 用戶端都支援 TLS。All gRPC client implementations support TLS. 從其他語言 gRPC 用戶端時,通常需要使用 SslCredentials 來設定通道。gRPC clients from other languages typically require the channel configured with SslCredentials. SslCredentials 指定用戶端將使用的憑證,而且必須用來取代不安全的認證。SslCredentials specifies the certificate that the client will use, and it must be used instead of insecure credentials. 如需將不同的 gRPC 用戶端執行設定為使用 TLS 的範例,請參閱GRPC AuthenticationFor examples of configuring the different gRPC client implementations to use TLS, see gRPC Authentication.

使用不受信任/不正確憑證呼叫 gRPC 服務Call a gRPC service with an untrusted/invalid certificate

.NET gRPC 用戶端要求服務必須具有受信任的憑證。The .NET gRPC client requires the service to have a trusted certificate. 呼叫沒有受信任憑證的 gRPC 服務時,會傳回下列錯誤訊息:The following error message is returned when calling a gRPC service without a trusted certificate:

未處理的例外狀況。Unhandled exception. System.net.HTTP.HTTPrequestexception:無法建立 SSL 連線,請參閱內部例外狀況。System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> AuthenticationException:根據驗證程式,遠端憑證是不正確。---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

如果您要在本機測試您的應用程式,而且 ASP.NET Core HTTPS 開發憑證不受信任,您可能會看到此錯誤。You may see this error if you are testing your app locally and the ASP.NET Core HTTPS development certificate is not trusted. 如需修正此問題的指示,請參閱信任 Windows 和 macOS上的 ASP.NET Core HTTPS 開發憑證For instructions to fix this issue, see Trust the ASP.NET Core HTTPS development certificate on Windows and macOS.

如果您是在另一部電腦上呼叫 gRPC 服務,而無法信任憑證,則可以將 gRPC 用戶端設定為忽略不正確憑證。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. 下列程式碼會使用HttpClientHandler來允許沒有受信任憑證的呼叫: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);

警告

不受信任的憑證應該只在應用程式開發期間使用。Untrusted certificates should only be used during app development. 生產應用程式應該一律使用有效的憑證。Production apps should always use valid certificates.

使用 .NET Core 用戶端呼叫不安全的 gRPC 服務Call insecure gRPC services with .NET Core client

需要其他設定,才能使用 .NET Core 用戶端呼叫不安全的 gRPC 服務。Additional configuration is required to call insecure gRPC services with the .NET Core client. GRPC 用戶端必須將 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport 參數設定為 true,並在伺服器位址中使用 httpThe 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);

無法在 macOS 上啟動 ASP.NET Core gRPC 應用程式Unable to start ASP.NET Core gRPC app on macOS

Kestrel 不支援 macOS 上的 TLS 和舊版 Windows (例如 Windows 7)上的 HTTP/2。Kestrel doesn't support HTTP/2 with TLS on macOS and older Windows versions such as Windows 7. ASP.NET Core gRPC 範本和範例預設會使用 TLS。The ASP.NET Core gRPC template and samples use TLS by default. 當您嘗試啟動 gRPC 伺服器時,您會看到下列錯誤訊息:You'll see the following error message when you attempt to start the gRPC server:

無法在 IPv4 回送介面上系結至 https://localhost:5001 :由於遺漏 ALPN 支援,macOS 上不支援 HTTP/2 over TLS。 '。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.'.

若要解決此問題,請將 Kestrel 和 gRPC 用戶端設定為使用沒有TLS 的 HTTP/2。To work around this issue, configure Kestrel and the gRPC client to use HTTP/2 without TLS. 您應該只在開發期間執行此動作。You should only do this during development. 不使用 TLS 會導致傳送未加密的 gRPC 訊息。Not using TLS will result in gRPC messages being sent without encryption.

Kestrel 必須在Program.cs中設定沒有 TLS 的 HTTP/2 端點: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>();
        });

設定 HTTP/2 端點而不使用 TLS 時,端點的listenoptions 來必須設定為 HttpProtocols.Http2When an HTTP/2 endpoint is configured without TLS, the endpoint's ListenOptions.Protocols must be set to HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 無法使用,因為需要 TLS 才能協調 HTTP/2。HttpProtocols.Http1AndHttp2 can't be used because TLS is required to negotiate HTTP/2. 如果沒有 TLS,端點的所有連接都會預設為 HTTP/1.1,而 gRPC 呼叫會失敗。Without TLS, all connections to the endpoint default to HTTP/1.1, and gRPC calls fail.

GRPC 用戶端也必須設定為不使用 TLS。The gRPC client must also be configured to not use TLS. 如需詳細資訊,請參閱使用 .Net Core 用戶端呼叫不安全的 gRPC 服務For more information, see Call insecure gRPC services with .NET Core client.

警告

只有在應用程式開發期間,才應該使用不含 TLS 的 HTTP/2。HTTP/2 without TLS should only be used during app development. 生產應用程式應該一律使用傳輸安全性。Production apps should always use transport security. 如需詳細資訊,請參閱gRPC for ASP.NET Core 中的安全性考慮For more information, see Security considerations in gRPC for ASP.NET Core.

gRPC C#資產不是從 proto 檔案產生的程式碼gRPC C# assets are not code generated from .proto files

gRPC 程式碼產生具體的用戶端和服務基類需要從專案參考 protobuf 檔案和工具。gRPC code generation of concrete clients and service base classes requires protobuf files and tooling to be referenced from a project. 您必須包括:You must include:

  • 您想要在 @no__t 1 專案群組中使用的 . proto檔案。.proto files you want to use in the <Protobuf> item group. 專案必須參考已匯入的proto 檔案。Imported .proto files must be referenced by the project.
  • GRPC 工具套件gRPC的套件參考。Package reference to the gRPC tooling package Grpc.Tools.

如需產生 gRPC C#資產的詳細資訊,請參閱 搭配 C# 的 gRPC 服務For more information on generating gRPC C# assets, see 搭配 C# 的 gRPC 服務.

根據預設,<Protobuf> 參考會產生具體的用戶端和服務基類。By default, a <Protobuf> reference generates a concrete client and a service base class. Reference 元素的 GrpcServices 屬性可以用來限制C#資產產生。The reference element's GrpcServices attribute can be used to limit C# asset generation. 有效的 GrpcServices 選項為:Valid GrpcServices options are:

  • Both (不存在時的預設值)Both (default when not present)
  • Server
  • Client
  • None

裝載 gRPC 服務的 ASP.NET Core web 應用程式只需要產生服務基類: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>

建立 gRPC 呼叫的 gRPC 用戶端應用程式只需要產生的具體用戶端:A gRPC client app making gRPC calls only needs the concrete client generated:

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

WPF 專案無法從 proto 檔案C#產生 gRPC 資產WPF projects unable to generate gRPC C# assets from .proto files

WPF 專案有一個已知的問題,導致 gRPC 程式碼產生無法正常運作。WPF projects have a known issue that prevents gRPC code generation from working correctly. 在 WPF 專案中,藉由參考 Grpc.Toolsproto檔案所產生的任何 gRPC 類型,會在使用時建立編譯錯誤:Any gRPC types generated in a WPF project by referencing Grpc.Tools and .proto files will create compilation errors when used:

錯誤 CS0246:找不到類型或命名空間名稱 ' MyGrpcServices ' (您是否遺漏 using 指示詞或元件參考?)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. 建立新的 .NET Core 類別庫專案。Create a new .NET Core class library project.
  2. 在新的專案中,新增參考以 C#從 * 檔中啟用程式碼產生:In the new project, add references to enable C# code generation from *.proto files:
    • 將套件參考新增至Grpc套件。Add a package reference to Grpc.Tools package.
    • * 的檔案新增至 @no__t 2 專案群組。Add *.proto files to the <Protobuf> item group.
  3. 在 WPF 應用程式中,加入新專案的參考。In the WPF application, add a reference to the new project.

WPF 應用程式可以從新的類別庫專案使用 gRPC 產生的類型。The WPF application can use the gRPC generated types from the new class library project.

Azure App Service 不支援 gRPCgRPC not supported on Azure App Service

警告

Azure App Service 或 IIS 目前不支援ASP.NET Core gRPCASP.NET Core gRPC is not currently supported on Azure App Service or IIS. Http.sys 的 HTTP/2 執行不支援 gRPC 所依賴的 HTTP 回應尾端標頭。The HTTP/2 implementation of Http.Sys does not support HTTP response trailing headers which gRPC relies on. 如需詳細資訊,請參閱 < 此 GitHub 問題For more information, see this GitHub issue.