Udostępnij za pośrednictwem


Rozwiązywanie problemów z usługą gRPC na platformie .NET

Autor: James Newton-King

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

W tym dokumencie omówiono często występujące problemy podczas tworzenia aplikacji gRPC na platformie .NET.

Niezgodność między konfiguracją protokołu SSL/TLS klienta i usługi

Szablon gRPC i przykłady używają protokołu Transport Layer Security (TLS) do zabezpieczania usług gRPC domyślnie. Klienci gRPC muszą pomyślnie wywoływać zabezpieczone usługi gRPC przy użyciu bezpiecznego połączenia.

Możesz sprawdzić, czy usługa gRPC platformy ASP.NET Core używa protokołu TLS w dziennikach zapisanych podczas uruchamiania aplikacji. Usługa nasłuchuje w punkcie końcowym 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

Klient platformy .NET Core musi używać https w adresie serwera, aby wykonywać wywołania z zabezpieczonym połączeniem:

var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);

Wszystkie implementacje klienta gRPC obsługują protokół TLS. Klienci gRPC z innych języków zwykle wymagają kanału skonfigurowanego za pomocą SslCredentialspolecenia . SslCredentials Określa certyfikat, którego będzie używać klient, i musi być używany zamiast niezabezpieczonych poświadczeń. Przykłady konfigurowania różnych implementacji klienta gRPC do używania protokołu TLS można znaleźć w temacie gRPC Authentication (Uwierzytelnianie gRPC).

Wywoływanie usługi gRPC z niezaufanym/nieprawidłowym certyfikatem

Klient gRPC platformy .NET wymaga, aby usługa miała zaufany certyfikat. Podczas wywoływania usługi gRPC bez zaufanego certyfikatu jest zwracany następujący komunikat o błędzie:

Nieobsługiwany wyjątek. System.Net.Http.HttpRequestException: Nie można ustanowić połączenia SSL, zobacz wyjątek wewnętrzny. >--- System.Security.Authentication.AuthenticationException: Certyfikat zdalny jest nieprawidłowy zgodnie z procedurą weryfikacji.

Ten błąd może wystąpić, jeśli testujesz aplikację lokalnie, a certyfikat dewelopera ASP.NET Core HTTPS nie jest zaufany. Aby uzyskać instrukcje dotyczące rozwiązania tego problemu, zobacz Ufaj certyfikatowi programistycznemu https platformy ASP.NET Core w systemach Windows i macOS.

Jeśli wywołujesz usługę gRPC na innym komputerze i nie możesz ufać certyfikatowi, można skonfigurować klienta gRPC tak, aby zignorował nieprawidłowy certyfikat. Poniższy kod używa HttpClientHandler.ServerCertificateCustomValidationCallback metody do zezwalania na wywołania bez zaufanego certyfikatu:

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

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

Fabryka klienta gRPC umożliwia wywołania bez zaufanego certyfikatu. ConfigurePrimaryHttpMessageHandler Użyj metody rozszerzenia, aby skonfigurować program obsługi na kliencie:


var services = new ServiceCollection();

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

        return handler;
    });

Ostrzeżenie

Niezaufane certyfikaty powinny być używane tylko podczas tworzenia aplikacji. Aplikacje produkcyjne powinny zawsze używać prawidłowych certyfikatów.

Wywoływanie niezabezpieczonych usług gRPC za pomocą klienta platformy .NET Core

Klient gRPC platformy .NET może wywoływać niezabezpieczone usługi gRPC, określając http adres serwera. Na przykład GrpcChannel.ForAddress("http://localhost:5000").

Istnieją pewne dodatkowe wymagania dotyczące wywoływania niezabezpieczonych usług gRPC w zależności od wersji platformy .NET używanej przez aplikację:

Ważne

Niezabezpieczone usługi gRPC muszą być hostowane na porcie tylko http/2. Aby uzyskać więcej informacji, zobacz ASP.NET core negocjacji protokołu.

Nie można uruchomić aplikacji gRPC platformy ASP.NET Core w systemie macOS

Kestrel nie obsługuje protokołu HTTP/2 z protokołem TLS w systemie macOS przed platformą .NET 8. Szablon ASP.NET Core gRPC i przykłady domyślnie używają protokołu TLS. Podczas próby uruchomienia serwera gRPC zostanie wyświetlony następujący komunikat o błędzie:

Nie można powiązać z https://localhost:5001 interfejsem sprzężenia zwrotnego protokołu IPv4: "Protokół HTTP/2 za pośrednictwem protokołu TLS nie jest obsługiwany w systemie macOS z powodu braku obsługi alpn".

Aby obejść ten problem na platformie .NET 7 i starszych wersjach, skonfiguruj Kestrel i klienta gRPC do używania protokołu HTTP/2 bez protokołu TLS. Należy to zrobić tylko podczas opracowywania. Nieużywane protokoły TLS spowodują wysyłanie komunikatów gRPC bez szyfrowania. Aby uzyskać więcej informacji, zobacz Asp.Net Core 7.0: Nie można uruchomić aplikacji gRPC platformy ASP.NET Core w systemie macOS.

Zasoby języka C# gRPC nie są kodami wygenerowanymi na podstawie .proto plików

Generowanie kodu gRPC konkretnych klientów i klas bazowych usługi wymaga odwoływania się do plików protobuf i narzędzi z projektu. Musisz uwzględnić następujące elementy:

Aby uzyskać więcej informacji na temat generowania zasobów gRPC C#, zobacz usługi gRPC w języku C#.

Aplikacja internetowa ASP.NET Core hostująca usługi gRPC wymaga tylko wygenerowanej klasy bazowej usługi:

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

Aplikacja kliencka gRPC wykonująca wywołania gRPC wymaga tylko wygenerowanego konkretnego klienta:

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

Projekty WPF nie mogą wygenerować zasobów gRPC C# z .proto plików

Projekty WPF mają znany problem uniemożliwiający poprawne działanie generowania kodu gRPC. Wszystkie typy gRPC wygenerowane w projekcie WPF przez odwołanie Grpc.Tools i .proto pliki będą tworzyć błędy kompilacji w przypadku użycia:

błąd CS0246: Nie można odnaleźć nazwy typu lub przestrzeni nazw "MyGrpcServices" (czy brakuje dyrektywy using lub odwołania do zestawu?)

Ten problem można obejść, wykonując następujące czynności:

  1. Utwórz nowy projekt biblioteki klas platformy .NET Core.
  2. W nowym projekcie dodaj odwołania, aby włączyć generowanie kodu w języku C# z .proto plików:
  3. W aplikacji WPF dodaj odwołanie do nowego projektu.

Aplikacja WPF może używać typów wygenerowanych przez gRPC z nowego projektu biblioteki klas.

Wywoływanie usług gRPC hostowanych w podkatalogu

Ostrzeżenie

Wiele narzędzi gRPC innych firm nie obsługuje usług hostowanych w podkatalogach. Rozważ znalezienie sposobu hostowania gRPC jako katalogu głównego.

Składnik ścieżki adresu kanału gRPC jest ignorowany podczas wykonywania wywołań gRPC. Na przykład GrpcChannel.ForAddress("https://localhost:5001/ignored_path") nie będzie używany ignored_path podczas routingu wywołań gRPC dla usługi.

Ścieżka adresu jest ignorowana, ponieważ gRPC ma ustandaryzowaną, preskrypcyjną strukturę adresów. Adres gRPC łączy nazwy pakietu, usługi i metody: https://localhost:5001/PackageName.ServiceName/MethodName.

Istnieją pewne scenariusze, w których aplikacja musi zawierać ścieżkę z wywołaniami gRPC. Na przykład gdy aplikacja gRPC platformy ASP.NET Core jest hostowana w katalogu usług IIS, a katalog musi zostać uwzględniony w żądaniu. Gdy ścieżka jest wymagana, można ją dodać do wywołania gRPC przy użyciu niestandardowego SubdirectoryHandler określonego poniżej:

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 jest używany podczas tworzenia kanału gRPC.

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

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

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

Powyższy kod ma następujące działanie:

  • Tworzy obiekt SubdirectoryHandler ze ścieżką /MyApp.
  • Konfiguruje kanał do użycia .SubdirectoryHandler
  • Wywołuje usługę gRPC za pomocą polecenia SayHelloAsync. Wywołanie gRPC jest wysyłane do .https://localhost:5001/MyApp/greet.Greeter/SayHello

Alternatywnie fabrykę klienta można skonfigurować SubdirectoryHandler przy użyciu polecenia AddHttpMessageHandler.

Konfigurowanie klienta gRPC do używania protokołu HTTP/3

Klient gRPC platformy .NET obsługuje protokół HTTP/3 z platformą .NET 6 lub nowszą wersją. Jeśli serwer wysyła alt-svc nagłówek odpowiedzi do klienta, który wskazuje, że serwer obsługuje protokół HTTP/3, klient automatycznie uaktualni połączenie z protokołem HTTP/3. Aby uzyskać więcej informacji, zobacz Use HTTP/3 with the ASP.NET Core web server (Używanie protokołu HTTP/3 z serwerem internetowym ASP.NET CoreKestrel).

Element DelegatingHandler może służyć do wymuszenia użycia protokołu HTTP/3 przez klienta gRPC. Wymuszanie protokołu HTTP/3 pozwala uniknąć narzutów związanych z uaktualnianiem żądania. Wymuś http/3 z kodem podobnym do następującego:

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 jest używany podczas tworzenia kanału gRPC. Poniższy kod tworzy kanał skonfigurowany do używania programu Http3Handler.

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

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

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

Alternatywnie fabrykę klienta można skonfigurować Http3Handler przy użyciu polecenia AddHttpMessageHandler.

Tworzenie gRPC w systemie Alpine Linux

Pakiet Grpc.Tools generuje typy .NET z .proto plików przy użyciu pakietu natywnego pliku binarnego o nazwie protoc. Dodatkowe kroki są wymagane do tworzenia aplikacji gRPC na platformach, które nie są obsługiwane przez natywne pliki binarne w systemie Grpc.Tools, takich jak Alpine Linux.

Generowanie kodu z wyprzedzeniem

Jednym z rozwiązań jest wygenerowanie kodu z wyprzedzeniem.

  1. Przenieś .proto pliki i Grpc.Tools odwołanie do pakietu do nowego projektu.
  2. Opublikuj projekt jako pakiet NuGet i przekaż go do źródła danych NuGet.
  3. Zaktualizuj aplikację, aby odwoływać się do pakietu NuGet.

W poprzednich krokach aplikacja nie wymaga Grpc.Tools już kompilowania, ponieważ kod jest generowany z wyprzedzeniem.

Dostosowywanie Grpc.Tools natywnych plików binarnych

Grpc.Tools obsługuje używanie niestandardowych natywnych plików binarnych. Ta funkcja umożliwia uruchamianie narzędzi gRPC w środowiskach, w których są dołączone pliki binarne natywne, nie są obsługiwane.

Kompilowanie lub uzyskiwanie i grpc_csharp_plugin natywnych protoc plików binarnych oraz konfigurowanie Grpc.Tools ich używania. Skonfiguruj natywne pliki binarne, ustawiając następujące zmienne środowiskowe:

  • PROTOBUF_PROTOC - Pełna ścieżka do kompilatora protokołu
  • GRPC_PROTOC_PLUGIN - Pełna ścieżka do grpc_csharp_plugin

W przypadku systemu Alpine Linux dostępne są pakiety udostępnione przez społeczność dla kompilatora protokołu i wtyczek gRPC w witrynie https://pkgs.alpinelinux.org/.

# Build or install the binaries for your architecture.

# 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

Aby uzyskać więcej informacji na temat używania Grpc.Tools z nieobsługiwanymi architekturami, zobacz dokumentację integracji kompilacji gRPC.

Limit czasu wywołania gRPC z HttpClient.Timeout

HttpClient jest domyślnie skonfigurowany z limitem czasu 100 sekund. GrpcChannel Jeśli element jest skonfigurowany do używania , długotrwałe wywołania przesyłania strumieniowego HttpClientgRPC zostaną anulowane, jeśli nie zostaną ukończone w limicie czasu.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Istnieje kilka sposobów naprawienia tego błędu. Pierwszą z nich jest skonfigurowanie HttpClient.Timeout do większej wartości. Timeout.InfiniteTimeSpan wyłącza limit czasu:

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

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

Możesz też unikać tworzenia i ustawiania HttpClient GrpcChannel.HttpHandler :

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

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

W tym dokumencie omówiono często występujące problemy podczas tworzenia aplikacji gRPC na platformie .NET.

Niezgodność między konfiguracją protokołu SSL/TLS klienta i usługi

Szablon gRPC i przykłady używają protokołu Transport Layer Security (TLS) do zabezpieczania usług gRPC domyślnie. Klienci gRPC muszą pomyślnie wywoływać zabezpieczone usługi gRPC przy użyciu bezpiecznego połączenia.

Możesz sprawdzić, czy usługa gRPC platformy ASP.NET Core używa protokołu TLS w dziennikach zapisanych podczas uruchamiania aplikacji. Usługa nasłuchuje w punkcie końcowym 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

Klient platformy .NET Core musi używać https w adresie serwera, aby wykonywać wywołania z zabezpieczonym połączeniem:

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

Wszystkie implementacje klienta gRPC obsługują protokół TLS. Klienci gRPC z innych języków zwykle wymagają kanału skonfigurowanego za pomocą SslCredentialspolecenia . SslCredentials Określa certyfikat, którego będzie używać klient, i musi być używany zamiast niezabezpieczonych poświadczeń. Przykłady konfigurowania różnych implementacji klienta gRPC do używania protokołu TLS można znaleźć w temacie gRPC Authentication (Uwierzytelnianie gRPC).

Wywoływanie usługi gRPC z niezaufanym/nieprawidłowym certyfikatem

Klient gRPC platformy .NET wymaga, aby usługa miała zaufany certyfikat. Podczas wywoływania usługi gRPC bez zaufanego certyfikatu jest zwracany następujący komunikat o błędzie:

Nieobsługiwany wyjątek. System.Net.Http.HttpRequestException: Nie można ustanowić połączenia SSL, zobacz wyjątek wewnętrzny. >--- System.Security.Authentication.AuthenticationException: Certyfikat zdalny jest nieprawidłowy zgodnie z procedurą weryfikacji.

Ten błąd może wystąpić, jeśli testujesz aplikację lokalnie, a certyfikat dewelopera ASP.NET Core HTTPS nie jest zaufany. Aby uzyskać instrukcje dotyczące rozwiązania tego problemu, zobacz Ufaj certyfikatowi programistycznemu https platformy ASP.NET Core w systemach Windows i macOS.

Jeśli wywołujesz usługę gRPC na innym komputerze i nie możesz ufać certyfikatowi, można skonfigurować klienta gRPC tak, aby zignorował nieprawidłowy certyfikat. Poniższy kod używa HttpClientHandler.ServerCertificateCustomValidationCallback metody do zezwalania na wywołania bez zaufanego certyfikatu:

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

Fabryka klienta gRPC umożliwia wywołania bez zaufanego certyfikatu. ConfigurePrimaryHttpMessageHandler Użyj metody rozszerzenia, aby skonfigurować program obsługi na kliencie:

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

        return handler;
    });

Ostrzeżenie

Niezaufane certyfikaty powinny być używane tylko podczas tworzenia aplikacji. Aplikacje produkcyjne powinny zawsze używać prawidłowych certyfikatów.

Wywoływanie niezabezpieczonych usług gRPC za pomocą klienta platformy .NET Core

Klient gRPC platformy .NET może wywoływać niezabezpieczone usługi gRPC, określając http adres serwera. Na przykład GrpcChannel.ForAddress("http://localhost:5000").

Istnieją pewne dodatkowe wymagania dotyczące wywoływania niezabezpieczonych usług gRPC w zależności od wersji platformy .NET używanej przez aplikację:

  • Program .NET 5 lub nowszy wymaga klienta Grpc.Net.Client w wersji 2.32.0 lub nowszej.

  • Program .NET Core 3.x wymaga dodatkowej konfiguracji. Aplikacja musi ustawić System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport przełącznik na true:

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

Przełącznik System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport jest wymagany tylko dla platformy .NET Core 3.x. Nic nie robi na platformie .NET 5 i nie jest wymagane.

Ważne

Niezabezpieczone usługi gRPC muszą być hostowane na porcie tylko http/2. Aby uzyskać więcej informacji, zobacz ASP.NET core negocjacji protokołu.

Nie można uruchomić aplikacji gRPC platformy ASP.NET Core w systemie macOS

Kestrel nie obsługuje protokołu HTTP/2 z protokołem TLS w systemie macOS przed platformą .NET 8. Szablon ASP.NET Core gRPC i przykłady domyślnie używają protokołu TLS. Podczas próby uruchomienia serwera gRPC zostanie wyświetlony następujący komunikat o błędzie:

Nie można powiązać z https://localhost:5001 interfejsem sprzężenia zwrotnego protokołu IPv4: "Protokół HTTP/2 za pośrednictwem protokołu TLS nie jest obsługiwany w systemie macOS z powodu braku obsługi alpn".

Aby obejść ten problem na platformie .NET 7 i starszych wersjach, skonfiguruj Kestrel i klienta gRPC do używania protokołu HTTP/2 bez protokołu TLS. Należy to zrobić tylko podczas opracowywania. Nieużywane protokoły TLS spowodują wysyłanie komunikatów gRPC bez szyfrowania.

Kestrel musi skonfigurować punkt końcowy HTTP/2 bez protokołu TLS w programie Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Setup a HTTP/2 endpoint without TLS.
    options.ListenLocalhost(<5287>, o => o.Protocols =
        HttpProtocols.Http2);
});
  • W poprzednim kodzie zastąp HTTP numer portu localhost numerem 5287 portu (nie HTTPS) określonym w Properties/launchSettings.json projekcie usługi gRPC.

Po skonfigurowaniu punktu końcowego HTTP/2 bez protokołu TLS punkt końcowy ListenOptions.Protocols musi mieć wartość HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 Nie można użyć, ponieważ protokół TLS jest wymagany do negocjowania protokołu HTTP/2. Bez protokołu TLS wszystkie połączenia z punktem końcowym domyślnie do protokołu HTTP/1.1 i wywołania gRPC kończą się niepowodzeniem.

Klient gRPC musi być również skonfigurowany tak, aby nie używał protokołu TLS. Aby uzyskać więcej informacji, zobacz Wywoływanie niezabezpieczonych usług gRPC za pomocą klienta platformy .NET Core.

Ostrzeżenie

Protokół HTTP/2 bez protokołu TLS powinien być używany tylko podczas tworzenia aplikacji. Aplikacje produkcyjne powinny zawsze używać zabezpieczeń transportu. Aby uzyskać więcej informacji, zobacz Zagadnienia dotyczące zabezpieczeń w gRPC dla ASP.NET Core.

Zasoby języka C# gRPC nie są kodami wygenerowanymi na podstawie .proto plików

Generowanie kodu gRPC konkretnych klientów i klas bazowych usługi wymaga odwoływania się do plików protobuf i narzędzi z projektu. Musisz uwzględnić następujące elementy:

Aby uzyskać więcej informacji na temat generowania zasobów gRPC C#, zobacz usługi gRPC w języku C#.

Aplikacja internetowa ASP.NET Core hostująca usługi gRPC wymaga tylko wygenerowanej klasy bazowej usługi:

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

Aplikacja kliencka gRPC wykonująca wywołania gRPC wymaga tylko wygenerowanego konkretnego klienta:

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

Projekty WPF nie mogą wygenerować zasobów gRPC C# z .proto plików

Projekty WPF mają znany problem uniemożliwiający poprawne działanie generowania kodu gRPC. Wszystkie typy gRPC wygenerowane w projekcie WPF przez odwołanie Grpc.Tools i .proto pliki będą tworzyć błędy kompilacji w przypadku użycia:

błąd CS0246: Nie można odnaleźć nazwy typu lub przestrzeni nazw "MyGrpcServices" (czy brakuje dyrektywy using lub odwołania do zestawu?)

Ten problem można obejść, wykonując następujące czynności:

  1. Utwórz nowy projekt biblioteki klas platformy .NET Core.
  2. W nowym projekcie dodaj odwołania, aby włączyć generowanie kodu w języku C# z .proto plików:
  3. W aplikacji WPF dodaj odwołanie do nowego projektu.

Aplikacja WPF może używać typów wygenerowanych przez gRPC z nowego projektu biblioteki klas.

Wywoływanie usług gRPC hostowanych w podkatalogu

Ostrzeżenie

Wiele narzędzi gRPC innych firm nie obsługuje usług hostowanych w podkatalogach. Rozważ znalezienie sposobu hostowania gRPC jako katalogu głównego.

Składnik ścieżki adresu kanału gRPC jest ignorowany podczas wykonywania wywołań gRPC. Na przykład GrpcChannel.ForAddress("https://localhost:5001/ignored_path") nie będzie używany ignored_path podczas routingu wywołań gRPC dla usługi.

Ścieżka adresu jest ignorowana, ponieważ gRPC ma ustandaryzowaną, preskrypcyjną strukturę adresów. Adres gRPC łączy nazwy pakietu, usługi i metody: https://localhost:5001/PackageName.ServiceName/MethodName.

Istnieją pewne scenariusze, w których aplikacja musi zawierać ścieżkę z wywołaniami gRPC. Na przykład gdy aplikacja gRPC platformy ASP.NET Core jest hostowana w katalogu usług IIS, a katalog musi zostać uwzględniony w żądaniu. Gdy ścieżka jest wymagana, można ją dodać do wywołania gRPC przy użyciu niestandardowego SubdirectoryHandler określonego poniżej:

/// <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 jest używany podczas tworzenia kanału 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" });

Powyższy kod ma następujące działanie:

  • Tworzy obiekt SubdirectoryHandler ze ścieżką /MyApp.
  • Konfiguruje kanał do użycia .SubdirectoryHandler
  • Wywołuje usługę gRPC za pomocą polecenia SayHelloAsync. Wywołanie gRPC jest wysyłane do .https://localhost:5001/MyApp/greet.Greeter/SayHello

Alternatywnie fabrykę klienta można skonfigurować SubdirectoryHandler przy użyciu polecenia AddHttpMessageHandler.

Konfigurowanie klienta gRPC do używania protokołu HTTP/3

Klient gRPC platformy .NET obsługuje protokół HTTP/3 z platformą .NET 6 lub nowszą wersją. Jeśli serwer wysyła alt-svc nagłówek odpowiedzi do klienta, który wskazuje, że serwer obsługuje protokół HTTP/3, klient automatycznie uaktualni połączenie z protokołem HTTP/3. Aby uzyskać informacje na temat włączania protokołu HTTP/3 na serwerze, zobacz Używanie protokołu HTTP/3 z serwerem internetowym ASP.NET CoreKestrel.

Obsługa protokołu HTTP/3 na platformie .NET 8 jest domyślnie włączona. Obsługa protokołu HTTP/3 na platformie .NET 6 i .NET 7 musi być włączona za pośrednictwem flagi konfiguracji w pliku projektu:

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

System.Net.SocketsHttpHandler.Http3Support można również ustawić przy użyciu elementu AppContext.SetSwitch.

Element DelegatingHandler może służyć do wymuszenia użycia protokołu HTTP/3 przez klienta gRPC. Wymuszanie protokołu HTTP/3 pozwala uniknąć narzutów związanych z uaktualnianiem żądania. Wymuś http/3 z kodem podobnym do następującego:

/// <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 jest używany podczas tworzenia kanału gRPC. Poniższy kod tworzy kanał skonfigurowany do używania programu 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" });

Alternatywnie fabrykę klienta można skonfigurować Http3Handler przy użyciu polecenia AddHttpMessageHandler.

Tworzenie gRPC w systemie Alpine Linux

Pakiet Grpc.Tools generuje typy .NET z .proto plików przy użyciu pakietu natywnego pliku binarnego o nazwie protoc. Dodatkowe kroki są wymagane do tworzenia aplikacji gRPC na platformach, które nie są obsługiwane przez natywne pliki binarne w systemie Grpc.Tools, takich jak Alpine Linux.

Generowanie kodu z wyprzedzeniem

Jednym z rozwiązań jest wygenerowanie kodu z wyprzedzeniem.

  1. Przenieś .proto pliki i Grpc.Tools odwołanie do pakietu do nowego projektu.
  2. Opublikuj projekt jako pakiet NuGet i przekaż go do źródła danych NuGet.
  3. Zaktualizuj aplikację, aby odwoływać się do pakietu NuGet.

W poprzednich krokach aplikacja nie wymaga Grpc.Tools już kompilowania, ponieważ kod jest generowany z wyprzedzeniem.

Dostosowywanie Grpc.Tools natywnych plików binarnych

Grpc.Tools obsługuje używanie niestandardowych natywnych plików binarnych. Ta funkcja umożliwia uruchamianie narzędzi gRPC w środowiskach, w których są dołączone pliki binarne natywne, nie są obsługiwane.

Kompilowanie lub uzyskiwanie i grpc_csharp_plugin natywnych protoc plików binarnych oraz konfigurowanie Grpc.Tools ich używania. Skonfiguruj natywne pliki binarne, ustawiając następujące zmienne środowiskowe:

  • PROTOBUF_PROTOC - Pełna ścieżka do kompilatora protokołu
  • GRPC_PROTOC_PLUGIN - Pełna ścieżka do grpc_csharp_plugin

W przypadku systemu Alpine Linux dostępne są pakiety udostępnione przez społeczność dla kompilatora protokołu i wtyczek gRPC w witrynie https://pkgs.alpinelinux.org/.

# Build or install the binaries for your architecture.

# 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

Aby uzyskać więcej informacji na temat używania Grpc.Tools z nieobsługiwanymi architekturami, zobacz dokumentację integracji kompilacji gRPC.

Limit czasu wywołania gRPC z HttpClient.Timeout

HttpClient jest domyślnie skonfigurowany z limitem czasu 100 sekund. GrpcChannel Jeśli element jest skonfigurowany do używania , długotrwałe wywołania przesyłania strumieniowego HttpClientgRPC zostaną anulowane, jeśli nie zostaną ukończone w limicie czasu.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Istnieje kilka sposobów naprawienia tego błędu. Pierwszą z nich jest skonfigurowanie HttpClient.Timeout do większej wartości. Timeout.InfiniteTimeSpan wyłącza limit czasu:

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

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

Możesz też unikać tworzenia i ustawiania HttpClient GrpcChannel.HttpHandler :

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

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

W tym dokumencie omówiono często występujące problemy podczas tworzenia aplikacji gRPC na platformie .NET.

Niezgodność między konfiguracją protokołu SSL/TLS klienta i usługi

Szablon gRPC i przykłady używają protokołu Transport Layer Security (TLS) do zabezpieczania usług gRPC domyślnie. Klienci gRPC muszą pomyślnie wywoływać zabezpieczone usługi gRPC przy użyciu bezpiecznego połączenia.

Możesz sprawdzić, czy usługa gRPC platformy ASP.NET Core używa protokołu TLS w dziennikach zapisanych podczas uruchamiania aplikacji. Usługa nasłuchuje w punkcie końcowym 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

Klient platformy .NET Core musi używać https w adresie serwera, aby wykonywać wywołania z zabezpieczonym połączeniem:

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

Wszystkie implementacje klienta gRPC obsługują protokół TLS. Klienci gRPC z innych języków zwykle wymagają kanału skonfigurowanego za pomocą SslCredentialspolecenia . SslCredentials Określa certyfikat, którego będzie używać klient, i musi być używany zamiast niezabezpieczonych poświadczeń. Przykłady konfigurowania różnych implementacji klienta gRPC do używania protokołu TLS można znaleźć w temacie gRPC Authentication (Uwierzytelnianie gRPC).

Wywoływanie usługi gRPC z niezaufanym/nieprawidłowym certyfikatem

Klient gRPC platformy .NET wymaga, aby usługa miała zaufany certyfikat. Podczas wywoływania usługi gRPC bez zaufanego certyfikatu jest zwracany następujący komunikat o błędzie:

Nieobsługiwany wyjątek. System.Net.Http.HttpRequestException: Nie można ustanowić połączenia SSL, zobacz wyjątek wewnętrzny. >--- System.Security.Authentication.AuthenticationException: Certyfikat zdalny jest nieprawidłowy zgodnie z procedurą weryfikacji.

Ten błąd może wystąpić, jeśli testujesz aplikację lokalnie, a certyfikat dewelopera ASP.NET Core HTTPS nie jest zaufany. Aby uzyskać instrukcje dotyczące rozwiązania tego problemu, zobacz Ufaj certyfikatowi programistycznemu https platformy ASP.NET Core w systemach Windows i macOS.

Jeśli wywołujesz usługę gRPC na innym komputerze i nie możesz ufać certyfikatowi, można skonfigurować klienta gRPC tak, aby zignorował nieprawidłowy certyfikat. Poniższy kod używa HttpClientHandler.ServerCertificateCustomValidationCallback metody do zezwalania na wywołania bez zaufanego certyfikatu:

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

Fabryka klienta gRPC umożliwia wywołania bez zaufanego certyfikatu. ConfigurePrimaryHttpMessageHandler Użyj metody rozszerzenia, aby skonfigurować program obsługi na kliencie:

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

        return handler;
    });

Ostrzeżenie

Niezaufane certyfikaty powinny być używane tylko podczas tworzenia aplikacji. Aplikacje produkcyjne powinny zawsze używać prawidłowych certyfikatów.

Wywoływanie niezabezpieczonych usług gRPC za pomocą klienta platformy .NET Core

Klient gRPC platformy .NET może wywoływać niezabezpieczone usługi gRPC, określając http adres serwera. Na przykład GrpcChannel.ForAddress("http://localhost:5000").

Istnieją pewne dodatkowe wymagania dotyczące wywoływania niezabezpieczonych usług gRPC w zależności od wersji platformy .NET używanej przez aplikację:

  • Program .NET 5 lub nowszy wymaga klienta Grpc.Net.Client w wersji 2.32.0 lub nowszej.

  • Program .NET Core 3.x wymaga dodatkowej konfiguracji. Aplikacja musi ustawić System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport przełącznik na true:

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

Przełącznik System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport jest wymagany tylko dla platformy .NET Core 3.x. Nic nie robi na platformie .NET 5 i nie jest wymagane.

Ważne

Niezabezpieczone usługi gRPC muszą być hostowane na porcie tylko http/2. Aby uzyskać więcej informacji, zobacz ASP.NET core negocjacji protokołu.

Nie można uruchomić aplikacji gRPC platformy ASP.NET Core w systemie macOS

Kestrel nie obsługuje protokołu HTTP/2 z protokołem TLS w systemie macOS przed platformą .NET 8. Szablon ASP.NET Core gRPC i przykłady domyślnie używają protokołu TLS. Podczas próby uruchomienia serwera gRPC zostanie wyświetlony następujący komunikat o błędzie:

Nie można powiązać z https://localhost:5001 interfejsem sprzężenia zwrotnego protokołu IPv4: "Protokół HTTP/2 za pośrednictwem protokołu TLS nie jest obsługiwany w systemie macOS z powodu braku obsługi alpn".

Aby obejść ten problem na platformie .NET 7 i starszych wersjach, skonfiguruj Kestrel i klienta gRPC do używania protokołu HTTP/2 bez protokołu TLS. Należy to zrobić tylko podczas opracowywania. Nieużywane protokoły TLS spowodują wysyłanie komunikatów gRPC bez szyfrowania.

Kestrel musi skonfigurować punkt końcowy HTTP/2 bez protokołu TLS w programie 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>();
        });

Po skonfigurowaniu punktu końcowego HTTP/2 bez protokołu TLS punkt końcowy ListenOptions.Protocols musi mieć wartość HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 Nie można użyć, ponieważ protokół TLS jest wymagany do negocjowania protokołu HTTP/2. Bez protokołu TLS wszystkie połączenia z punktem końcowym domyślnie do protokołu HTTP/1.1 i wywołania gRPC kończą się niepowodzeniem.

Klient gRPC musi być również skonfigurowany tak, aby nie używał protokołu TLS. Aby uzyskać więcej informacji, zobacz Wywoływanie niezabezpieczonych usług gRPC za pomocą klienta platformy .NET Core.

Ostrzeżenie

Protokół HTTP/2 bez protokołu TLS powinien być używany tylko podczas tworzenia aplikacji. Aplikacje produkcyjne powinny zawsze używać zabezpieczeń transportu. Aby uzyskać więcej informacji, zobacz Zagadnienia dotyczące zabezpieczeń w gRPC dla ASP.NET Core.

Zasoby języka C# gRPC nie są kodami wygenerowanymi na podstawie .proto plików

Generowanie kodu gRPC konkretnych klientów i klas bazowych usługi wymaga odwoływania się do plików protobuf i narzędzi z projektu. Musisz uwzględnić następujące elementy:

Aby uzyskać więcej informacji na temat generowania zasobów gRPC C#, zobacz usługi gRPC w języku C#.

Aplikacja internetowa ASP.NET Core hostująca usługi gRPC wymaga tylko wygenerowanej klasy bazowej usługi:

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

Aplikacja kliencka gRPC wykonująca wywołania gRPC wymaga tylko wygenerowanego konkretnego klienta:

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

Projekty WPF nie mogą wygenerować zasobów gRPC C# z .proto plików

Projekty WPF mają znany problem uniemożliwiający poprawne działanie generowania kodu gRPC. Wszystkie typy gRPC wygenerowane w projekcie WPF przez odwołanie Grpc.Tools i .proto pliki będą tworzyć błędy kompilacji w przypadku użycia:

błąd CS0246: Nie można odnaleźć nazwy typu lub przestrzeni nazw "MyGrpcServices" (czy brakuje dyrektywy using lub odwołania do zestawu?)

Ten problem można obejść, wykonując następujące czynności:

  1. Utwórz nowy projekt biblioteki klas platformy .NET Core.
  2. W nowym projekcie dodaj odwołania, aby włączyć generowanie kodu w języku C# z .proto plików:
  3. W aplikacji WPF dodaj odwołanie do nowego projektu.

Aplikacja WPF może używać typów wygenerowanych przez gRPC z nowego projektu biblioteki klas.

Wywoływanie usług gRPC hostowanych w podkatalogu

Ostrzeżenie

Wiele narzędzi gRPC innych firm nie obsługuje usług hostowanych w podkatalogach. Rozważ znalezienie sposobu hostowania gRPC jako katalogu głównego.

Składnik ścieżki adresu kanału gRPC jest ignorowany podczas wykonywania wywołań gRPC. Na przykład GrpcChannel.ForAddress("https://localhost:5001/ignored_path") nie będzie używany ignored_path podczas routingu wywołań gRPC dla usługi.

Ścieżka adresu jest ignorowana, ponieważ gRPC ma ustandaryzowaną, preskrypcyjną strukturę adresów. Adres gRPC łączy nazwy pakietu, usługi i metody: https://localhost:5001/PackageName.ServiceName/MethodName.

Istnieją pewne scenariusze, w których aplikacja musi zawierać ścieżkę z wywołaniami gRPC. Na przykład gdy aplikacja gRPC platformy ASP.NET Core jest hostowana w katalogu usług IIS, a katalog musi zostać uwzględniony w żądaniu. Gdy ścieżka jest wymagana, można ją dodać do wywołania gRPC przy użyciu niestandardowego SubdirectoryHandler określonego poniżej:

/// <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 jest używany podczas tworzenia kanału 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" });

Powyższy kod ma następujące działanie:

  • Tworzy obiekt SubdirectoryHandler ze ścieżką /MyApp.
  • Konfiguruje kanał do użycia .SubdirectoryHandler
  • Wywołuje usługę gRPC za pomocą polecenia SayHelloAsync. Wywołanie gRPC jest wysyłane do .https://localhost:5001/MyApp/greet.Greeter/SayHello

Alternatywnie fabrykę klienta można skonfigurować SubdirectoryHandler przy użyciu polecenia AddHttpMessageHandler.

Limit czasu wywołania gRPC z HttpClient.Timeout

HttpClient jest domyślnie skonfigurowany z limitem czasu 100 sekund. GrpcChannel Jeśli element jest skonfigurowany do używania , długotrwałe wywołania przesyłania strumieniowego HttpClientgRPC zostaną anulowane, jeśli nie zostaną ukończone w limicie czasu.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Istnieje kilka sposobów naprawienia tego błędu. Pierwszą z nich jest skonfigurowanie HttpClient.Timeout do większej wartości. Timeout.InfiniteTimeSpan wyłącza limit czasu:

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

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

Możesz też unikać tworzenia i ustawiania HttpClient GrpcChannel.HttpHandler :

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

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

W tym dokumencie omówiono często występujące problemy podczas tworzenia aplikacji gRPC na platformie .NET.

Niezgodność między konfiguracją protokołu SSL/TLS klienta i usługi

Szablon gRPC i przykłady używają protokołu Transport Layer Security (TLS) do zabezpieczania usług gRPC domyślnie. Klienci gRPC muszą pomyślnie wywoływać zabezpieczone usługi gRPC przy użyciu bezpiecznego połączenia.

Możesz sprawdzić, czy usługa gRPC platformy ASP.NET Core używa protokołu TLS w dziennikach zapisanych podczas uruchamiania aplikacji. Usługa nasłuchuje w punkcie końcowym 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

Klient platformy .NET Core musi używać https w adresie serwera, aby wykonywać wywołania z zabezpieczonym połączeniem:

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

Wszystkie implementacje klienta gRPC obsługują protokół TLS. Klienci gRPC z innych języków zwykle wymagają kanału skonfigurowanego za pomocą SslCredentialspolecenia . SslCredentials Określa certyfikat, którego będzie używać klient, i musi być używany zamiast niezabezpieczonych poświadczeń. Przykłady konfigurowania różnych implementacji klienta gRPC do używania protokołu TLS można znaleźć w temacie gRPC Authentication (Uwierzytelnianie gRPC).

Wywoływanie usługi gRPC z niezaufanym/nieprawidłowym certyfikatem

Klient gRPC platformy .NET wymaga, aby usługa miała zaufany certyfikat. Podczas wywoływania usługi gRPC bez zaufanego certyfikatu jest zwracany następujący komunikat o błędzie:

Nieobsługiwany wyjątek. System.Net.Http.HttpRequestException: Nie można ustanowić połączenia SSL, zobacz wyjątek wewnętrzny. >--- System.Security.Authentication.AuthenticationException: Certyfikat zdalny jest nieprawidłowy zgodnie z procedurą weryfikacji.

Ten błąd może wystąpić, jeśli testujesz aplikację lokalnie, a certyfikat dewelopera ASP.NET Core HTTPS nie jest zaufany. Aby uzyskać instrukcje dotyczące rozwiązania tego problemu, zobacz Ufaj certyfikatowi programistycznemu https platformy ASP.NET Core w systemach Windows i macOS.

Jeśli wywołujesz usługę gRPC na innym komputerze i nie możesz ufać certyfikatowi, można skonfigurować klienta gRPC tak, aby zignorował nieprawidłowy certyfikat. Poniższy kod używa HttpClientHandler.ServerCertificateCustomValidationCallback metody do zezwalania na wywołania bez zaufanego certyfikatu:

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

Fabryka klienta gRPC umożliwia wywołania bez zaufanego certyfikatu. ConfigurePrimaryHttpMessageHandler Użyj metody rozszerzenia, aby skonfigurować program obsługi na kliencie:

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

        return handler;
    });

Ostrzeżenie

Niezaufane certyfikaty powinny być używane tylko podczas tworzenia aplikacji. Aplikacje produkcyjne powinny zawsze używać prawidłowych certyfikatów.

Wywoływanie niezabezpieczonych usług gRPC za pomocą klienta platformy .NET Core

Klient gRPC platformy .NET może wywoływać niezabezpieczone usługi gRPC, określając http adres serwera. Na przykład GrpcChannel.ForAddress("http://localhost:5000").

Istnieją pewne dodatkowe wymagania dotyczące wywoływania niezabezpieczonych usług gRPC w zależności od wersji platformy .NET używanej przez aplikację:

  • Program .NET 5 lub nowszy wymaga klienta Grpc.Net.Client w wersji 2.32.0 lub nowszej.

  • Program .NET Core 3.x wymaga dodatkowej konfiguracji. Aplikacja musi ustawić System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport przełącznik na true:

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

Przełącznik System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport jest wymagany tylko dla platformy .NET Core 3.x. Nic nie robi na platformie .NET 5 i nie jest wymagane.

Ważne

Niezabezpieczone usługi gRPC muszą być hostowane na porcie tylko http/2. Aby uzyskać więcej informacji, zobacz ASP.NET core negocjacji protokołu.

Nie można uruchomić aplikacji gRPC platformy ASP.NET Core w systemie macOS

Kestrel nie obsługuje protokołu HTTP/2 z protokołem TLS w systemie macOS przed platformą .NET 8. Szablon ASP.NET Core gRPC i przykłady domyślnie używają protokołu TLS. Podczas próby uruchomienia serwera gRPC zostanie wyświetlony następujący komunikat o błędzie:

Nie można powiązać z https://localhost:5001 interfejsem sprzężenia zwrotnego protokołu IPv4: "Protokół HTTP/2 za pośrednictwem protokołu TLS nie jest obsługiwany w systemie macOS z powodu braku obsługi alpn".

Aby obejść ten problem na platformie .NET 7 i starszych wersjach, skonfiguruj Kestrel i klienta gRPC do używania protokołu HTTP/2 bez protokołu TLS. Należy to zrobić tylko podczas opracowywania. Nieużywane protokoły TLS spowodują wysyłanie komunikatów gRPC bez szyfrowania.

Kestrel musi skonfigurować punkt końcowy HTTP/2 bez protokołu TLS w programie 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>();
        });

Po skonfigurowaniu punktu końcowego HTTP/2 bez protokołu TLS punkt końcowy ListenOptions.Protocols musi mieć wartość HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 Nie można użyć, ponieważ protokół TLS jest wymagany do negocjowania protokołu HTTP/2. Bez protokołu TLS wszystkie połączenia z punktem końcowym domyślnie do protokołu HTTP/1.1 i wywołania gRPC kończą się niepowodzeniem.

Klient gRPC musi być również skonfigurowany tak, aby nie używał protokołu TLS. Aby uzyskać więcej informacji, zobacz Wywoływanie niezabezpieczonych usług gRPC za pomocą klienta platformy .NET Core.

Ostrzeżenie

Protokół HTTP/2 bez protokołu TLS powinien być używany tylko podczas tworzenia aplikacji. Aplikacje produkcyjne powinny zawsze używać zabezpieczeń transportu. Aby uzyskać więcej informacji, zobacz Zagadnienia dotyczące zabezpieczeń w gRPC dla ASP.NET Core.

Zasoby języka C# gRPC nie są kodami wygenerowanymi na podstawie .proto plików

Generowanie kodu gRPC konkretnych klientów i klas bazowych usługi wymaga odwoływania się do plików protobuf i narzędzi z projektu. Musisz uwzględnić następujące elementy:

Aby uzyskać więcej informacji na temat generowania zasobów gRPC C#, zobacz usługi gRPC w języku C#.

Aplikacja internetowa ASP.NET Core hostująca usługi gRPC wymaga tylko wygenerowanej klasy bazowej usługi:

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

Aplikacja kliencka gRPC wykonująca wywołania gRPC wymaga tylko wygenerowanego konkretnego klienta:

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

Projekty WPF nie mogą wygenerować zasobów gRPC C# z .proto plików

Projekty WPF mają znany problem uniemożliwiający poprawne działanie generowania kodu gRPC. Wszystkie typy gRPC wygenerowane w projekcie WPF przez odwołanie Grpc.Tools i .proto pliki będą tworzyć błędy kompilacji w przypadku użycia:

błąd CS0246: Nie można odnaleźć nazwy typu lub przestrzeni nazw "MyGrpcServices" (czy brakuje dyrektywy using lub odwołania do zestawu?)

Ten problem można obejść, wykonując następujące czynności:

  1. Utwórz nowy projekt biblioteki klas platformy .NET Core.
  2. W nowym projekcie dodaj odwołania, aby włączyć generowanie kodu w języku C# z .proto plików:
  3. W aplikacji WPF dodaj odwołanie do nowego projektu.

Aplikacja WPF może używać typów wygenerowanych przez gRPC z nowego projektu biblioteki klas.

Wywoływanie usług gRPC hostowanych w podkatalogu

Ostrzeżenie

Wiele narzędzi gRPC innych firm nie obsługuje usług hostowanych w podkatalogach. Rozważ znalezienie sposobu hostowania gRPC jako katalogu głównego.

Składnik ścieżki adresu kanału gRPC jest ignorowany podczas wykonywania wywołań gRPC. Na przykład GrpcChannel.ForAddress("https://localhost:5001/ignored_path") nie będzie używany ignored_path podczas routingu wywołań gRPC dla usługi.

Ścieżka adresu jest ignorowana, ponieważ gRPC ma ustandaryzowaną, preskrypcyjną strukturę adresów. Adres gRPC łączy nazwy pakietu, usługi i metody: https://localhost:5001/PackageName.ServiceName/MethodName.

Istnieją pewne scenariusze, w których aplikacja musi zawierać ścieżkę z wywołaniami gRPC. Na przykład gdy aplikacja gRPC platformy ASP.NET Core jest hostowana w katalogu usług IIS, a katalog musi zostać uwzględniony w żądaniu. Gdy ścieżka jest wymagana, można ją dodać do wywołania gRPC przy użyciu niestandardowego SubdirectoryHandler określonego poniżej:

/// <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 jest używany podczas tworzenia kanału 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" });

Powyższy kod ma następujące działanie:

  • Tworzy obiekt SubdirectoryHandler ze ścieżką /MyApp.
  • Konfiguruje kanał do użycia .SubdirectoryHandler
  • Wywołuje usługę gRPC za pomocą polecenia SayHelloAsync. Wywołanie gRPC jest wysyłane do .https://localhost:5001/MyApp/greet.Greeter/SayHello

Alternatywnie fabrykę klienta można skonfigurować SubdirectoryHandler przy użyciu polecenia AddHttpMessageHandler.

Limit czasu wywołania gRPC z HttpClient.Timeout

HttpClient jest domyślnie skonfigurowany z limitem czasu 100 sekund. GrpcChannel Jeśli element jest skonfigurowany do używania , długotrwałe wywołania przesyłania strumieniowego HttpClientgRPC zostaną anulowane, jeśli nie zostaną ukończone w limicie czasu.

System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.

Istnieje kilka sposobów naprawienia tego błędu. Pierwszą z nich jest skonfigurowanie HttpClient.Timeout do większej wartości. Timeout.InfiniteTimeSpan wyłącza limit czasu:

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

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

Możesz też unikać tworzenia i ustawiania HttpClient GrpcChannel.HttpHandler :

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

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