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

作者:James Newton-King

注意

這不是本文的最新版本。 若要切換至最新版本,請使用目錄頂端 ASP.NET Core版本選取器。

版本選取器

如果選取器在窄瀏覽器視窗中看不到,請擴大視窗,或選取垂直省略號 (⋮) >目錄

目錄選取器

本檔討論在 .NET 上開發 gRPC 應用程式時常見的問題。

用戶端和服務 SSL/TLS 組態不符

gRPC 範本和範例預設會使用 傳輸層安全性 (TLS) 來保護 gRPC 服務。 gRPC 用戶端必須使用安全連線,才能成功呼叫受保護的 gRPC 服務。

您可以在應用程式啟動時寫入的記錄中使用 TLS,確認 gRPC 服務 ASP.NET Core。 服務將在 HTTPS 端點上接聽:

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 ,才能使用安全連線進行呼叫:

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。 來自其他語言的 gRPC 用戶端通常需要使用 設定的 SslCredentials 通道。 SslCredentials 指定用戶端將使用的憑證,而且必須使用憑證,而不是不安全的認證。 如需將不同 gRPC 用戶端實作設定為使用 TLS 的範例,請參閱 gRPC 驗證

使用不受信任的/無效憑證呼叫 gRPC 服務

.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 來允許沒有受信任憑證的呼叫:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

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

gRPC 用戶端處理站允許在沒有受信任憑證的情況下呼叫。 ConfigurePrimaryHttpMessageHandler使用擴充方法在用戶端上設定處理常式:

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

警告

不受信任的憑證應該只在應用程式開發期間使用。 生產應用程式應該一律使用有效的憑證。

使用 .NET Core 用戶端呼叫不安全的 gRPC 服務

.NET gRPC 用戶端可以藉由在 http 伺服器位址中指定來呼叫不安全的 gRPC 服務。 例如: GrpcChannel.ForAddress("http://localhost:5000")

根據應用程式正在使用的 .NET 版本,呼叫不安全的 gRPC 服務有一些額外需求:

  • .NET 5 或更新版本需要 Grpc.Net.Client 2.32.0 版或更新版本。

  • .NET Core 3.x 需要額外的設定。 應用程式必須將 參數設定 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupporttrue

    // 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);
    

System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport只有 .NET Core 3.x 才需要參數。 它不會在 .NET 5 中執行任何動作,而且不需要。

重要

不安全的 gRPC 服務必須裝載于僅限 HTTP/2 的埠上。 如需詳細資訊,請參閱ASP.NET Core通訊協定交涉

無法在 macOS 上啟動 ASP.NET Core gRPC 應用程式

Kestrel 在 .NET 8 之前,不支援在 macOS 上使用 TLS 的 HTTP/2。 ASP.NET Core gRPC 範本和範例預設會使用 TLS。 當您嘗試啟動 gRPC 伺服器時,您會看到下列錯誤訊息:

無法在 IPv4 回送介面上系結至 https://localhost:5001 :「macOS 不支援 HTTP/2 over TLS,因為缺少 ALPN 支援。」。

若要在 .NET 7 和更早版本中解決此問題,請將 Kestrel 和 gRPC 用戶端設定為 不使用 TLS 的 HTTP/2。 您應該只在開發期間執行此動作。 不使用 TLS 會導致 gRPC 訊息在沒有加密的情況下傳送。

Kestrel 必須在 中 Program.cs 設定不含 TLS 的 HTTP/2 端點:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Setup a HTTP/2 endpoint without TLS.
    options.ListenLocalhost(<5287>, o => o.Protocols =
        HttpProtocols.Http2);
});
  • 在上述程式碼中,將 localhost 埠號碼 5287 取代為 HTTP gRPC 服務專案中指定的 Properties/launchSettings.json (未 HTTPS) 埠號碼。

在沒有 TLS 的情況下設定 HTTP/2 端點時,端點的 ListenOptions.Protocols 必須設定為 HttpProtocols.Http2HttpProtocols.Http1AndHttp2 無法使用,因為需要 TLS 才能交涉 HTTP/2。 如果沒有 TLS,端點的所有連線都會預設為 HTTP/1.1,而 gRPC 呼叫會失敗。

gRPC 用戶端也必須設定為不使用 TLS。 如需詳細資訊,請參閱 使用 .NET Core 用戶端呼叫不安全的 gRPC 服務

警告

不含 TLS 的 HTTP/2 應該只在應用程式開發期間使用。 生產應用程式應該一律使用傳輸安全性。 如需詳細資訊,請參閱gRPC 中適用于 ASP.NET Core 的安全性考慮

gRPC C# 資產不是從 .proto 檔案產生的程式碼

gRPC 程式碼產生具體用戶端和服務基類需要從專案參考 protobuf 檔案和工具。 您必須包含:

如需產生 gRPC C# 資產的詳細資訊,請參閱 使用 C# 的 gRPC 服務

裝載 gRPC 服務的 ASP.NET Core Web 應用程式只需要產生的服務基類:

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

進行 gRPC 呼叫的 gRPC 用戶端應用程式只需要產生的具體用戶端:

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

WPF 專案無法從 .proto 檔案產生 gRPC C# 資產

WPF 專案有 已知問題 ,導致 gRPC 程式碼產生無法正常運作。 參考 Grpc.Tools.proto 和 檔案時,在 WPF 專案中產生的任何 gRPC 類型都會在使用時建立編譯錯誤:

錯誤 CS0246:找不到類型或命名空間名稱 'MyGrpcServices', (遺漏 using 指示詞或元件參考嗎?)

您可以透過下列方式解決此問題:

  1. 建立新的 .NET Core 類別庫專案。
  2. 在新專案中,新增參考以 啟用檔案的 .proto C# 程式碼產生
  3. 在 WPF 應用程式中,新增新專案的參考。

WPF 應用程式可以使用來自新類別庫專案的 gRPC 產生的類型。

呼叫裝載于子目錄中的 gRPC 服務

警告

許多協力廠商 gRPC 工具不支援子目錄中裝載的服務。 請考慮尋找將 gRPC 裝載為根目錄的方法。

進行 gRPC 呼叫時,會忽略 gRPC 通道位址的路徑元件。 例如, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") 不會在路由傳送服務的 gRPC 呼叫時使用 ignored_path

因為 gRPC 具有標準化、規範的位址結構,所以會忽略位址路徑。 gRPC 位址結合了封裝、服務和方法名稱: https://localhost:5001/PackageName.ServiceName/MethodName

在某些情況下,應用程式需要包含具有 gRPC 呼叫的路徑。 例如,當 ASP.NET Core gRPC 應用程式裝載于 IIS 目錄中,且要求中必須包含目錄時。 需要路徑時,可以使用下列自訂的指定 SubdirectoryHandler ,將其新增至 gRPC 呼叫:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler 會在建立 gRPC 通道時使用。

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

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

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

上述程式碼:

  • SubdirectoryHandler使用路徑 /MyApp 建立 。
  • 設定通道以使用 SubdirectoryHandler
  • 使用 SayHelloAsync 呼叫 gRPC 服務。 gRPC 呼叫會傳送至 https://localhost:5001/MyApp/greet.Greeter/SayHello

或者,可以使用 SubdirectoryHandler 來設定 AddHttpMessageHandler 用戶端處理站。

將 gRPC 用戶端設定為使用 HTTP/3

.NET gRPC 用戶端支援 HTTP/3 與 .NET 6 或更新版本。 如果伺服器將回應標頭傳送 alt-svc 至指出伺服器支援 HTTP/3 的用戶端,用戶端會自動將其連線升級至 HTTP/3。 伺服器 Kestrel 預設支援 HTTP/3。 如需詳細資訊,請參閱搭配 ASP.NET Core Kestrel 網頁伺服器使用 HTTP/3

DelegatingHandler可用來強制 gRPC 用戶端使用 HTTP/3。 強制 HTTP/3 可避免升級要求的額外負荷。 強制使用類似下列程式碼的 HTTP/3:

/// <summary>
/// A delegating handler that changes the request HTTP version to HTTP/3.
/// </summary>
public class Http3Handler : DelegatingHandler
{
    public Http3Handler() { }
    public Http3Handler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

        return base.SendAsync(request, cancellationToken);
    }
}

Http3Handler 會在建立 gRPC 通道時使用。 下列程式碼會建立設定為使用 的 Http3Handler 通道。

var handler = new Http3Handler(new HttpClientHandler());

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

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

或者,可以使用 Http3Handler 來設定 AddHttpMessageHandler 用戶端處理站。

在 Alpine Linux 上建置 gRPC

套件 Grpc.Tools 會使用稱為 protoc 的配套原生二進位檔,從 .proto 檔案產生 .NET 類型。 在 中原生二進位檔 Grpc.Tools 不支援的平臺上建置 gRPC 應用程式,例如 Alpine Linux 所需的額外步驟。

事先產生程式碼

其中一個解決方案是事先產生程式碼。

  1. 將檔案和 Grpc.Tools 套件參考移至 .proto 新專案。
  2. 將專案發佈為 NuGet 套件,並將其上傳至 NuGet 摘要。
  3. 更新應用程式以參考 NuGet 套件。

在上述步驟中,應用程式不再需要 Grpc.Tools 建置,因為程式碼會事先產生。

自訂 Grpc.Tools 原生二進位檔

Grpc.Tools 支援使用自訂原生二進位檔。 此功能可讓 gRPC 工具在其配套的原生二進位檔不支援的環境中執行。

建置或取得 protocgrpc_csharp_plugin 原生二進位檔,並將其設定 Grpc.Tools 為使用這些二進位檔。 藉由設定下列環境變數來設定原生二進位檔:

  • PROTOBUF_PROTOC - 通訊協定緩衝區編譯器的完整路徑
  • GRPC_PROTOC_PLUGIN - grpc_csharp_plugin的完整路徑

針對 Alpine Linux,在 上提供通訊協定緩衝區編譯器和 gRPC 外掛程式的社群提供套件 https://pkgs.alpinelinux.org/

# Build or install the binaries for your architecture.

# e.g. for Alpine Linux the grpc-plugins package can be used
#  See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
apk add grpc-plugins  # Alpine Linux specific package installer

# Set environment variables for the built/installed protoc
# and grpc_csharp_plugin binaries
export PROTOBUF_PROTOC=/usr/bin/protoc
export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin

# When dotnet build runs, the Grpc.Tools NuGet package
# uses the binaries pointed to by the environment variables.
dotnet build

如需搭配不支援架構使用 Grpc.Tools 的詳細資訊,請參閱 gRPC 組建整合檔

本檔討論在 .NET 上開發 gRPC 應用程式時常見的問題。

用戶端和服務 SSL/TLS 組態不符

gRPC 範本和範例預設會使用 傳輸層安全性 (TLS) 來保護 gRPC 服務。 gRPC 用戶端必須使用安全連線,才能成功呼叫受保護的 gRPC 服務。

您可以在應用程式啟動時寫入的記錄中使用 TLS,確認 gRPC 服務 ASP.NET Core。 服務將在 HTTPS 端點上接聽:

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 ,才能使用安全連線進行呼叫:

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。 來自其他語言的 gRPC 用戶端通常需要使用 設定的 SslCredentials 通道。 SslCredentials 指定用戶端將使用的憑證,而且必須使用憑證,而不是不安全的認證。 如需將不同 gRPC 用戶端實作設定為使用 TLS 的範例,請參閱 gRPC 驗證

使用不受信任的/無效憑證呼叫 gRPC 服務

.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 來允許沒有受信任憑證的呼叫:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

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

gRPC 用戶端處理站允許在沒有受信任憑證的情況下呼叫。 ConfigurePrimaryHttpMessageHandler使用擴充方法在用戶端上設定處理常式:

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

警告

不受信任的憑證應該只在應用程式開發期間使用。 生產應用程式應該一律使用有效的憑證。

使用 .NET Core 用戶端呼叫不安全的 gRPC 服務

.NET gRPC 用戶端可以藉由在 http 伺服器位址中指定來呼叫不安全的 gRPC 服務。 例如: GrpcChannel.ForAddress("http://localhost:5000")

根據應用程式正在使用的 .NET 版本,呼叫不安全的 gRPC 服務有一些額外需求:

  • .NET 5 或更新版本需要 Grpc.Net.Client 2.32.0 版或更新版本。

  • .NET Core 3.x 需要額外的設定。 應用程式必須將 參數設定 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupporttrue

    // 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);
    

System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport只有 .NET Core 3.x 才需要參數。 它不會在 .NET 5 中執行任何動作,而且不需要。

重要

不安全的 gRPC 服務必須裝載于僅限 HTTP/2 的埠上。 如需詳細資訊,請參閱ASP.NET Core通訊協定交涉

無法在 macOS 上啟動 ASP.NET Core gRPC 應用程式

Kestrel 在 .NET 8 之前,不支援在 macOS 上使用 TLS 的 HTTP/2。 ASP.NET Core gRPC 範本和範例預設會使用 TLS。 當您嘗試啟動 gRPC 伺服器時,您會看到下列錯誤訊息:

無法在 IPv4 回送介面上系結至 https://localhost:5001 :「macOS 不支援 HTTP/2 over TLS,因為缺少 ALPN 支援。」。

若要在 .NET 7 和更早版本中解決此問題,請將 Kestrel 和 gRPC 用戶端設定為 不使用 TLS 的 HTTP/2。 您應該只在開發期間執行此動作。 不使用 TLS 會導致 gRPC 訊息在沒有加密的情況下傳送。

Kestrel 必須在 中 Program.cs 設定不含 TLS 的 HTTP/2 端點:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Setup a HTTP/2 endpoint without TLS.
    options.ListenLocalhost(<5287>, o => o.Protocols =
        HttpProtocols.Http2);
});
  • 在上述程式碼中,將 localhost 埠號碼 5287 取代為 HTTP gRPC 服務專案中指定的 Properties/launchSettings.json (未 HTTPS) 埠號碼。

在沒有 TLS 的情況下設定 HTTP/2 端點時,端點的 ListenOptions.Protocols 必須設定為 HttpProtocols.Http2HttpProtocols.Http1AndHttp2 無法使用,因為需要 TLS 才能交涉 HTTP/2。 如果沒有 TLS,端點的所有連線都會預設為 HTTP/1.1,而 gRPC 呼叫會失敗。

gRPC 用戶端也必須設定為不使用 TLS。 如需詳細資訊,請參閱 使用 .NET Core 用戶端呼叫不安全的 gRPC 服務

警告

不含 TLS 的 HTTP/2 應該只在應用程式開發期間使用。 生產應用程式應該一律使用傳輸安全性。 如需詳細資訊,請參閱gRPC 中適用于 ASP.NET Core 的安全性考慮

gRPC C# 資產不是從 .proto 檔案產生的程式碼

gRPC 程式碼產生具體用戶端和服務基類需要從專案參考 protobuf 檔案和工具。 您必須包含:

如需產生 gRPC C# 資產的詳細資訊,請參閱 使用 C# 的 gRPC 服務

裝載 gRPC 服務的 ASP.NET Core Web 應用程式只需要產生的服務基類:

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

進行 gRPC 呼叫的 gRPC 用戶端應用程式只需要產生的具體用戶端:

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

WPF 專案無法從 .proto 檔案產生 gRPC C# 資產

WPF 專案有 已知問題 ,導致 gRPC 程式碼產生無法正常運作。 參考 Grpc.Tools.proto 和 檔案時,在 WPF 專案中產生的任何 gRPC 類型都會在使用時建立編譯錯誤:

錯誤 CS0246:找不到類型或命名空間名稱 'MyGrpcServices', (遺漏 using 指示詞或元件參考嗎?)

您可以透過下列方式解決此問題:

  1. 建立新的 .NET Core 類別庫專案。
  2. 在新專案中,新增參考以 啟用檔案的 .proto C# 程式碼產生
  3. 在 WPF 應用程式中,新增新專案的參考。

WPF 應用程式可以使用來自新類別庫專案的 gRPC 產生的類型。

呼叫裝載于子目錄中的 gRPC 服務

警告

許多協力廠商 gRPC 工具不支援子目錄中裝載的服務。 請考慮尋找將 gRPC 裝載為根目錄的方法。

進行 gRPC 呼叫時,會忽略 gRPC 通道位址的路徑元件。 例如, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") 不會在路由傳送服務的 gRPC 呼叫時使用 ignored_path

因為 gRPC 具有標準化、規範的位址結構,所以會忽略位址路徑。 gRPC 位址結合了封裝、服務和方法名稱: https://localhost:5001/PackageName.ServiceName/MethodName

在某些情況下,應用程式需要包含具有 gRPC 呼叫的路徑。 例如,當 ASP.NET Core gRPC 應用程式裝載于 IIS 目錄中,且要求中必須包含目錄時。 需要路徑時,可以使用下列自訂的指定 SubdirectoryHandler ,將其新增至 gRPC 呼叫:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler 會在建立 gRPC 通道時使用。

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

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

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

上述程式碼:

  • SubdirectoryHandler使用路徑 /MyApp 建立 。
  • 設定通道以使用 SubdirectoryHandler
  • 使用 SayHelloAsync 呼叫 gRPC 服務。 gRPC 呼叫會傳送至 https://localhost:5001/MyApp/greet.Greeter/SayHello

或者,可以使用 SubdirectoryHandler 來設定 AddHttpMessageHandler 用戶端處理站。

將 gRPC 用戶端設定為使用 HTTP/3

.NET gRPC 用戶端支援 HTTP/3 與 .NET 6 或更新版本。 如果伺服器將回應標頭傳送 alt-svc 至指出伺服器支援 HTTP/3 的用戶端,用戶端會自動將其連線升級至 HTTP/3。 如需如何在伺服器上啟用 HTTP/3 的資訊,請參閱搭配 ASP.NET Core Kestrel Web 服務器使用 HTTP/3

預設會啟用 .NET 8 中的 HTTP/3 支援。 .NET 6 和 .NET 7 中的 HTTP/3 支援必須透過專案檔中的組態旗標來啟用:

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support" Value="true" />
</ItemGroup>

System.Net.SocketsHttpHandler.Http3Support 也可以使用 AppCoNtext.SetSwitch 來設定。

DelegatingHandler可用來強制 gRPC 用戶端使用 HTTP/3。 強制 HTTP/3 可避免升級要求的額外負荷。 強制使用類似下列程式碼的 HTTP/3:

/// <summary>
/// A delegating handler that changes the request HTTP version to HTTP/3.
/// </summary>
public class Http3Handler : DelegatingHandler
{
    public Http3Handler() { }
    public Http3Handler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

        return base.SendAsync(request, cancellationToken);
    }
}

Http3Handler 會在建立 gRPC 通道時使用。 下列程式碼會建立設定為使用 的 Http3Handler 通道。

var handler = new Http3Handler(new HttpClientHandler());

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

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

或者,可以使用 Http3Handler 來設定 AddHttpMessageHandler 用戶端處理站。

在 Alpine Linux 上建置 gRPC

套件 Grpc.Tools 會使用稱為 protoc 的配套原生二進位檔,從 .proto 檔案產生 .NET 類型。 在 中原生二進位檔 Grpc.Tools 不支援的平臺上建置 gRPC 應用程式,例如 Alpine Linux 所需的額外步驟。

事先產生程式碼

其中一個解決方案是事先產生程式碼。

  1. 將檔案和 Grpc.Tools 套件參考移至 .proto 新專案。
  2. 將專案發佈為 NuGet 套件,並將其上傳至 NuGet 摘要。
  3. 更新應用程式以參考 NuGet 套件。

在上述步驟中,應用程式不再需要 Grpc.Tools 建置,因為程式碼會事先產生。

自訂 Grpc.Tools 原生二進位檔

Grpc.Tools 支援使用自訂原生二進位檔。 此功能可讓 gRPC 工具在其配套的原生二進位檔不支援的環境中執行。

建置或取得 protocgrpc_csharp_plugin 原生二進位檔,並將其設定 Grpc.Tools 為使用這些二進位檔。 藉由設定下列環境變數來設定原生二進位檔:

  • PROTOBUF_PROTOC - 通訊協定緩衝區編譯器的完整路徑
  • GRPC_PROTOC_PLUGIN - grpc_csharp_plugin的完整路徑

針對 Alpine Linux,在 上提供通訊協定緩衝區編譯器和 gRPC 外掛程式的社群提供套件 https://pkgs.alpinelinux.org/

# Build or install the binaries for your architecture.

# e.g. for Alpine Linux the grpc-plugins package can be used
#  See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
apk add grpc-plugins  # Alpine Linux specific package installer

# Set environment variables for the built/installed protoc
# and grpc_csharp_plugin binaries
export PROTOBUF_PROTOC=/usr/bin/protoc
export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin

# When dotnet build runs, the Grpc.Tools NuGet package
# uses the binaries pointed to by the environment variables.
dotnet build

如需搭配不支援架構使用 Grpc.Tools 的詳細資訊,請參閱 gRPC 組建整合檔

本檔討論在 .NET 上開發 gRPC 應用程式時常見的問題。

用戶端和服務 SSL/TLS 組態不符

gRPC 範本和範例預設會使用 傳輸層安全性 (TLS) 來保護 gRPC 服務。 gRPC 用戶端必須使用安全連線,才能成功呼叫受保護的 gRPC 服務。

您可以在應用程式啟動時寫入的記錄中使用 TLS,確認 gRPC 服務 ASP.NET Core。 服務將在 HTTPS 端點上接聽:

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 ,才能使用安全連線進行呼叫:

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。 來自其他語言的 gRPC 用戶端通常需要使用 設定的 SslCredentials 通道。 SslCredentials 指定用戶端將使用的憑證,而且必須使用憑證,而不是不安全的認證。 如需將不同 gRPC 用戶端實作設定為使用 TLS 的範例,請參閱 gRPC 驗證

使用不受信任的/無效憑證呼叫 gRPC 服務

.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 來允許沒有受信任憑證的呼叫:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

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

gRPC 用戶端處理站允許在沒有受信任憑證的情況下呼叫。 ConfigurePrimaryHttpMessageHandler使用擴充方法在用戶端上設定處理常式:

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

警告

不受信任的憑證應該只在應用程式開發期間使用。 生產應用程式應該一律使用有效的憑證。

使用 .NET Core 用戶端呼叫不安全的 gRPC 服務

.NET gRPC 用戶端可以藉由在 http 伺服器位址中指定來呼叫不安全的 gRPC 服務。 例如: GrpcChannel.ForAddress("http://localhost:5000")

根據應用程式正在使用的 .NET 版本,呼叫不安全的 gRPC 服務有一些額外需求:

  • .NET 5 或更新版本需要 Grpc.Net.Client 2.32.0 版或更新版本。

  • .NET Core 3.x 需要額外的設定。 應用程式必須將 參數設定 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupporttrue

    // 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);
    

只有 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport .NET Core 3.x 才需要參數。 它不會在 .NET 5 中執行任何動作,而且不需要。

重要

不安全的 gRPC 服務必須裝載于僅限 HTTP/2 的埠上。 如需詳細資訊,請參閱ASP.NET Core通訊協定交涉

無法在 macOS 上啟動 ASP.NET Core gRPC 應用程式

Kestrel 在 .NET 8 之前,不支援在 macOS 上使用 TLS 的 HTTP/2。 ASP.NET Core gRPC 範本和範例預設會使用 TLS。 當您嘗試啟動 gRPC 伺服器時,您會看到下列錯誤訊息:

無法在 IPv4 回送介面上系結至 https://localhost:5001 :「macOS 不支援 HTTP/2 over TLS,因為缺少 ALPN 支援。」。

若要在 .NET 7 和更早版本中解決此問題,請將 和 gRPC 用戶端設定 Kestrel 為在沒有 TLS 的情況下 使用 HTTP/2。 您應該只在開發期間執行此動作。 不使用 TLS 會導致 gRPC 訊息在未加密的情況下傳送。

Kestrel 必須在 中 Program.cs 設定不含 TLS 的 HTTP/2 端點:

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>();
        });

在沒有 TLS 的情況下設定 HTTP/2 端點時,端點的 ListenOptions.Protocols 必須設定為 HttpProtocols.Http2HttpProtocols.Http1AndHttp2 無法使用,因為需要 TLS 才能交涉 HTTP/2。 如果沒有 TLS,端點的所有連線都會預設為 HTTP/1.1,而 gRPC 呼叫會失敗。

gRPC 用戶端也必須設定為不使用 TLS。 如需詳細資訊,請參閱 使用 .NET Core 用戶端呼叫不安全的 gRPC 服務

警告

不含 TLS 的 HTTP/2 應該只在應用程式開發期間使用。 生產應用程式應該一律使用傳輸安全性。 如需詳細資訊,請參閱gRPC 中適用于 ASP.NET Core 的安全性考慮

gRPC C# 資產不是從 .proto 檔案產生的程式碼

gRPC 程式碼產生具象用戶端和服務基類需要從專案參考 protobuf 檔案和工具。 您必須包含:

如需產生 gRPC C# 資產的詳細資訊,請參閱 使用 C# 的 gRPC 服務

裝載 gRPC 服務的 ASP.NET Core Web 應用程式只需要產生的服務基類:

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

進行 gRPC 呼叫的 gRPC 用戶端應用程式只需要產生的具體用戶端:

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

WPF 專案無法從 .proto 檔案產生 gRPC C# 資產

WPF 專案有 已知問題 ,可防止 gRPC 程式碼產生正常運作。 參考 Grpc.Tools.proto 和檔案會在使用時,在 WPF 專案中產生的任何 gRPC 類型都會建立編譯錯誤:

錯誤 CS0246:找不到類型或命名空間名稱 'MyGrpcServices', (遺漏 using 指示詞或元件參考?)

您可以透過下列方式解決此問題:

  1. 建立新的 .NET Core 類別庫專案。
  2. 在新專案中,新增參考以 啟用從 .proto 檔案產生 C# 程式碼
  3. 在 WPF 應用程式中,新增新專案的參考。

WPF 應用程式可以使用新類別庫專案中產生的 gRPC 型別。

呼叫裝載在子目錄中的 gRPC 服務

警告

許多協力廠商 gRPC 工具不支援子目錄中裝載的服務。 請考慮尋找將 gRPC 裝載為根目錄的方法。

進行 gRPC 呼叫時,會忽略 gRPC 通道位址的路徑元件。 例如, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") 在路由 gRPC 呼叫服務時,不會使用 ignored_path

因為 gRPC 具有標準化、規範的位址結構,所以會忽略位址路徑。 gRPC 位址結合了封裝、服務和方法名稱: https://localhost:5001/PackageName.ServiceName/MethodName

當應用程式需要包含 gRPC 呼叫的路徑時,有一些案例。 例如,當 ASP.NET Core gRPC 應用程式裝載于 IIS 目錄中,且該目錄必須包含在要求中時。 需要路徑時,可以使用下列自訂 SubdirectoryHandler 新增至 gRPC 呼叫:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler 會在建立 gRPC 通道時使用。

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

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

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

上述程式碼:

  • SubdirectoryHandler使用路徑 /MyApp 建立 。
  • 設定通道以使用 SubdirectoryHandler
  • 使用 SayHelloAsync 呼叫 gRPC 服務。 gRPC 呼叫會傳送至 https://localhost:5001/MyApp/greet.Greeter/SayHello

或者,您可以使用 SubdirectoryHandlerAddHttpMessageHandler 來設定用戶端處理站。

本檔討論在 .NET 上開發 gRPC 應用程式時常見的問題。

用戶端和服務 SSL/TLS 組態不符

gRPC 範本和範例預設會使用 傳輸層安全性 (TLS) 來保護 gRPC 服務。 gRPC 用戶端需要使用安全連線,才能成功呼叫受保護的 gRPC 服務。

您可以在應用程式啟動時寫入的記錄中,確認 gRPC 服務 ASP.NET Core使用 TLS。 服務將在 HTTPS 端點上接聽:

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 伺服器位址中使用 ,才能使用安全連線進行呼叫:

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。 來自其他語言的 gRPC 用戶端通常需要使用 設定的 SslCredentials 通道。 SslCredentials 會指定用戶端將使用的憑證,而且必須使用它,而不是不安全的認證。 如需設定不同 gRPC 用戶端實作以使用 TLS 的範例,請參閱 gRPC 驗證

使用不受信任/不正確憑證呼叫 gRPC 服務

.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 來允許沒有受信任憑證的呼叫:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

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

gRPC 用戶端處理站允許呼叫,而不需要受信任的憑證。 ConfigurePrimaryHttpMessageHandler使用擴充方法在用戶端上設定處理常式:

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

警告

不受信任的憑證只能在應用程式開發期間使用。 生產應用程式應該一律使用有效的憑證。

使用 .NET Core 用戶端呼叫不安全的 gRPC 服務

.NET gRPC 用戶端可以藉由在伺服器位址中指定 http 來呼叫不安全的 gRPC 服務。 例如: GrpcChannel.ForAddress("http://localhost:5000")

視應用程式正在使用的 .NET 版本而定,呼叫不安全的 gRPC 服務有一些額外需求:

  • .NET 5 或更新版本需要 Grpc.Net.Client 2.32.0 版或更新版本。

  • .NET Core 3.x 需要額外的設定。 應用程式必須將 參數設定 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupporttrue

    // 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);
    

只有 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport .NET Core 3.x 才需要參數。 它不會在 .NET 5 中執行任何動作,而且不需要。

重要

不安全的 gRPC 服務必須裝載于僅限 HTTP/2 的埠上。 如需詳細資訊,請參閱ASP.NET Core通訊協定交涉

無法在 macOS 上啟動 ASP.NET Core gRPC 應用程式

Kestrel 在 .NET 8 之前,不支援在 macOS 上使用 TLS 的 HTTP/2。 ASP.NET Core gRPC 範本和範例預設會使用 TLS。 當您嘗試啟動 gRPC 伺服器時,您會看到下列錯誤訊息:

無法在 IPv4 回送介面上系結至 https://localhost:5001 :「macOS 不支援 HTTP/2 over TLS,因為缺少 ALPN 支援。」。

若要在 .NET 7 和更早版本中解決此問題,請將 和 gRPC 用戶端設定 Kestrel 為在沒有 TLS 的情況下 使用 HTTP/2。 您應該只在開發期間執行此動作。 不使用 TLS 會導致 gRPC 訊息在未加密的情況下傳送。

Kestrel 必須在 中 Program.cs 設定不含 TLS 的 HTTP/2 端點:

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>();
        });

在沒有 TLS 的情況下設定 HTTP/2 端點時,端點的 ListenOptions.Protocols 必須設定為 HttpProtocols.Http2HttpProtocols.Http1AndHttp2 無法使用,因為需要 TLS 才能交涉 HTTP/2。 如果沒有 TLS,端點的所有連線都會預設為 HTTP/1.1,而 gRPC 呼叫會失敗。

gRPC 用戶端也必須設定為不使用 TLS。 如需詳細資訊,請參閱 使用 .NET Core 用戶端呼叫不安全的 gRPC 服務

警告

不含 TLS 的 HTTP/2 應該只在應用程式開發期間使用。 生產應用程式應該一律使用傳輸安全性。 如需詳細資訊,請參閱gRPC 中適用于 ASP.NET Core 的安全性考慮

gRPC C# 資產不是從 .proto 檔案產生的程式碼

gRPC 程式碼產生具象用戶端和服務基類需要從專案參考 protobuf 檔案和工具。 您必須包含:

如需產生 gRPC C# 資產的詳細資訊,請參閱 使用 C# 的 gRPC 服務

裝載 gRPC 服務的 ASP.NET Core Web 應用程式只需要產生的服務基類:

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

進行 gRPC 呼叫的 gRPC 用戶端應用程式只需要產生的具體用戶端:

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

WPF 專案無法從 .proto 檔案產生 gRPC C# 資產

WPF 專案有 已知問題 ,可防止 gRPC 程式碼產生正常運作。 參考 Grpc.Tools.proto 和檔案會在使用時,在 WPF 專案中產生的任何 gRPC 類型都會建立編譯錯誤:

錯誤 CS0246:找不到類型或命名空間名稱 'MyGrpcServices', (遺漏 using 指示詞或元件參考?)

您可以透過下列方式解決此問題:

  1. 建立新的 .NET Core 類別庫專案。
  2. 在新專案中,新增參考以 啟用從 .proto 檔案產生 C# 程式碼
  3. 在 WPF 應用程式中,新增新專案的參考。

WPF 應用程式可以使用新類別庫專案中產生的 gRPC 型別。

呼叫裝載在子目錄中的 gRPC 服務

警告

許多協力廠商 gRPC 工具不支援子目錄中裝載的服務。 請考慮尋找將 gRPC 裝載為根目錄的方法。

進行 gRPC 呼叫時,會忽略 gRPC 通道位址的路徑元件。 例如, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") 在路由 gRPC 呼叫服務時,不會使用 ignored_path

因為 gRPC 具有標準化、規範的位址結構,所以會忽略位址路徑。 gRPC 位址結合了封裝、服務和方法名稱: https://localhost:5001/PackageName.ServiceName/MethodName

當應用程式需要包含 gRPC 呼叫的路徑時,有一些案例。 例如,當 ASP.NET Core gRPC 應用程式裝載于 IIS 目錄中,且該目錄必須包含在要求中時。 需要路徑時,可以使用下列自訂 SubdirectoryHandler 新增至 gRPC 呼叫:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler 會在建立 gRPC 通道時使用。

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

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

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

上述程式碼:

  • SubdirectoryHandler使用路徑 /MyApp 建立 。
  • 設定通道以使用 SubdirectoryHandler
  • 使用 SayHelloAsync 呼叫 gRPC 服務。 gRPC 呼叫會傳送至 https://localhost:5001/MyApp/greet.Greeter/SayHello

或者,您可以使用 SubdirectoryHandlerAddHttpMessageHandler 來設定用戶端處理站。