Delen via


Problemen met gRPC in .NET oplossen

Door James Newton-King

Note

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikel voor de huidige release.

Warning

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 9-versie van dit artikel voor de huidige release.

Important

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikel voor de huidige release.

In dit document worden veelvoorkomende problemen besproken bij het ontwikkelen van gRPC-apps op .NET.

Niet-overeenkomende client- en service-SSL/TLS-configuratie

De gRPC-sjabloon en -voorbeelden gebruiken Tls (Transport Layer Security) om gRPC-services standaard te beveiligen. gRPC-clients moeten een beveiligde verbinding gebruiken om beveiligde gRPC-services aan te roepen.

U kunt controleren of de ASP.NET Core gRPC-service TLS gebruikt in de logboeken die zijn geschreven op het begin van de app. De service luistert op een HTTPS-eindpunt:

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

De .NET-client moet https in het serveradres gebruiken om oproepen te doen met een beveiligde verbinding:

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

Alle gRPC-client-implementaties ondersteunen TLS. gRPC-clients uit andere talen vereisen doorgaans het kanaal dat is geconfigureerd met SslCredentials. SslCredentials geeft het certificaat op dat de client gaat gebruiken en moet worden gebruikt in plaats van onveilige referenties. Zie gRPC-verificatie voor voorbeelden van het configureren van de verschillende gRPC-client-implementaties voor het gebruik van TLS.

Een gRPC-service aanroepen met een niet-vertrouwd/ongeldig certificaat

De .NET gRPC-client vereist dat de service een vertrouwd certificaat heeft. Het volgende foutbericht wordt geretourneerd bij het aanroepen van een gRPC-service zonder een vertrouwd certificaat:

Unhandled exception. System.Net.Http.HttpRequestException: de SSL-verbinding kan niet tot stand worden gebracht, zie interne uitzondering. >--- System.Security.Authentication.AuthenticationException: het externe certificaat is ongeldig volgens de validatieprocedure.

Deze fout kan optreden als u uw app lokaal test en het ASP.NET Core HTTPS-ontwikkelingscertificaat niet wordt vertrouwd. Zie Het ASP.NET Core HTTPS-ontwikkelingscertificaat vertrouwen in Windows en macOS voor instructies voor het oplossen van dit probleem.

Als u een gRPC-service aanroept op een andere computer en het certificaat niet kunt vertrouwen, kan de gRPC-client worden geconfigureerd om het ongeldige certificaat te negeren. De volgende code gebruikt HttpClientHandler.ServerCertificateCustomValidationCallback om aanroepen zonder een vertrouwd certificaat toe te staan:

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

De gRPC-clientfactory staat aanroepen toe zonder een vertrouwd certificaat. Gebruik de ConfigurePrimaryHttpMessageHandler extensiemethode om de handler op de client te configureren:


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

Warning

Niet-vertrouwde certificaten mogen alleen worden gebruikt tijdens het ontwikkelen van apps. Productie-apps moeten altijd geldige certificaten gebruiken.

Onveilige gRPC-services aanroepen met .NET-client

De .NET gRPC-client kan onveilige gRPC-services aanroepen door op te geven http in het serveradres. Bijvoorbeeld: GrpcChannel.ForAddress("http://localhost:5000").

Er zijn enkele aanvullende vereisten voor het aanroepen van onveilige gRPC-services, afhankelijk van de .NET-versie die een app gebruikt:

Important

Onveilige gRPC-services moeten worden gehost op een HTTP/2-poort. Zie ASP.NET Core-protocolonderhandeling voor meer informatie.

Kan ASP.NET Core gRPC-app niet starten in macOS

Kestrel biedt vóór .NET 8 geen ondersteuning voor HTTP/2 met TLS in macOS. De ASP.NET Core gRPC-sjabloon en voorbeelden maken standaard gebruik van TLS. U ziet het volgende foutbericht wanneer u probeert de gRPC-server te starten:

Kan geen verbinding maken met https://localhost:5001 de IPv4-loopback-interface: 'HTTP/2 via TLS wordt niet ondersteund op macOS vanwege ontbrekende ALPN-ondersteuning.'

Als u dit probleem in .NET 7 of eerder wilt omzeilen, configureert Kestrel u de gRPC-client en gebruikt u HTTP/2 zonder TLS. U moet dit alleen doen tijdens de ontwikkeling. Als u TLS niet gebruikt, worden gRPC-berichten zonder versleuteling verzonden. Zie ASP.NET Core in .NET 7: Kan ASP.NET Core gRPC-app niet starten op macOS voor meer informatie.

gRPC C#-assets zijn geen code gegenereerd uit .proto bestanden

Voor het genereren van gRPC-code van concrete clients en servicebasisklassen moeten protobuf-bestanden en -hulpprogramma's worden genoemd in een project. U moet het volgende opnemen:

  • .proto bestanden die u wilt gebruiken in de <Protobuf> itemgroep. Er moet naar geïmporteerde .proto bestanden worden verwezen door het project.
  • Pakketverwijzing naar het gRPC-hulpprogrammapakket Grpc.Tools.

Zie gRPC-services met C# voor meer informatie over het genereren van gRPC C#-assets.

Voor een ASP.NET Core-web-app die als host fungeert voor gRPC-services, hoeft alleen de servicebasisklasse te worden gegenereerd:

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

Een gRPC-client-app die gRPC-aanroepen doet, heeft alleen de concrete client nodig die is gegenereerd:

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

WPF-projecten kunnen geen gRPC C#-assets genereren uit .proto bestanden

WPF-projecten hebben een bekend probleem waardoor het genereren van gRPC-code niet correct werkt. Alle gRPC-typen die in een WPF-project worden gegenereerd door te verwijzen naar Grpc.Tools en .proto bestanden, zullen compilatiefouten veroorzaken wanneer ze worden gebruikt.

fout CS0246: Het type of de naamruimtenaam 'MyGrpcServices' is niet gevonden (ontbreekt er een using-instructie of een assemblyreferentie?)

U kunt dit probleem oplossen door:

  1. Maak een nieuw .NET-klassebibliotheekproject.
  2. Voeg in het nieuwe project verwijzingen toe om het genereren van C#-code uit .proto bestanden in te schakelen:
  3. Voeg in de WPF-toepassing een verwijzing toe naar het nieuwe project.

De WPF-toepassing kan gebruikmaken van de gegenereerde gRPC-typen uit het nieuwe klassebibliotheekproject.

GRPC-services aanroepen die worden gehost in een submap

Warning

Veel gRPC-hulpprogramma's van derden bieden geen ondersteuning voor services die worden gehost in submappen. Overweeg om een manier te vinden om gRPC als hoofdmap te hosten.

Het padonderdeel van het adres van een gRPC-kanaal wordt genegeerd bij het plaatsen van gRPC-aanroepen. Wordt bijvoorbeeld GrpcChannel.ForAddress("https://localhost:5001/ignored_path") niet gebruikt bij het routeren van gRPC-aanroepen voor de service ignored_path.

Het adrespad wordt genegeerd omdat gRPC een gestandaardiseerde, prescriptieve adresstructuur heeft. Een gRPC-adres combineert de pakket-, service- en methodenamen: https://localhost:5001/PackageName.ServiceName/MethodName.

Er zijn enkele scenario's waarin een app een pad met gRPC-aanroepen moet bevatten. Wanneer bijvoorbeeld een ASP.NET Core gRPC-app wordt gehost in een IIS-map en de map moet worden opgenomen in de aanvraag. Wanneer een pad is vereist, kan het worden toegevoegd aan de gRPC-aanroep met behulp van de aangepaste SubdirectoryHandler opgegeven hieronder:

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 wordt gebruikt wanneer het gRPC-kanaal wordt gemaakt.

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

De voorgaande code:

  • Hiermee maakt u een SubdirectoryHandler met het pad /MyApp.
  • Hiermee configureert u een kanaal om SubdirectoryHandler te gebruiken.
  • Roept de gRPC-service aan met SayHelloAsync. De gRPC-oproep wordt verzonden naar https://localhost:5001/MyApp/greet.Greeter/SayHello.

U kunt ook een clientfactory configureren met SubdirectoryHandler behulp van AddHttpMessageHandler.

GRPC-client configureren voor het gebruik van HTTP/3

De .NET gRPC-client ondersteunt HTTP/3 met .NET 6 of hoger. Als de server een alt-svc antwoordheader naar de client verzendt die aangeeft dat de server HTTP/3 ondersteunt, wordt de verbinding met HTTP/3 automatisch bijgewerkt. Zie HTTP/3 gebruiken met de ASP.NET Core-webserver Kestrelvoor meer informatie.

A DelegatingHandler kan worden gebruikt om een gRPC-client te dwingen HTTP/3 te gebruiken. Het afdwingen van HTTP/3 voorkomt de overhead van het upgraden van de aanvraag. Forceer HTTP/3 met code die vergelijkbaar is met de volgende:

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 wordt gebruikt wanneer het gRPC-kanaal wordt gemaakt. Met de volgende code wordt een kanaal gemaakt dat is geconfigureerd om Http3Handler te gebruiken.

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

U kunt ook een clientfactory configureren met Http3Handler behulp van AddHttpMessageHandler.

GRPC bouwen in Alpine Linux

Het Grpc.Tools pakket genereert .NET-typen van .proto bestanden met behulp van een gebundeld systeemeigen binair met de naam protoc. Aanvullende stappen zijn vereist voor het bouwen van gRPC-apps op platforms die niet worden ondersteund door de systeemeigen binaire bestanden in Grpc.Tools, zoals Alpine Linux.

Code van tevoren genereren

Een oplossing is om van tevoren code te genereren.

  1. Verplaats .proto bestanden en de Grpc.Tools pakketreferentie naar een nieuw project.
  2. Publiceer het project als een NuGet-pakket en upload het naar een NuGet-feed.
  3. Werk de app bij om te verwijzen naar het NuGet-pakket.

Met de voorgaande stappen hoeft Grpc.Tools de app niet meer te bouwen omdat code van tevoren wordt gegenereerd.

Systeemeigen binaire bestanden aanpassen Grpc.Tools

Grpc.Tools biedt ondersteuning voor het gebruik van aangepaste binaire bestanden. Met deze functie kan de gRPC-tooling worden uitgevoerd in omgevingen waar de geïntegreerde native binaries niet worden ondersteund.

Bouw of verkrijg protoc en grpc_csharp_plugin systeemeigen binaire bestanden en configureer Grpc.Tools om ze te gebruiken. Configureer systeemeigen binaire bestanden door de volgende omgevingsvariabelen in te stellen:

  • PROTOBUF_PROTOC - Volledig pad naar de compiler voor protocolbuffers
  • GRPC_PROTOC_PLUGIN - Volledig pad naar de grpc_csharp_plugin

Voor Alpine Linux zijn er door de community geleverde pakketten voor de protocolbuffers compiler en gRPC-invoegtoepassingen op 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

Zie de Grpc.Tools voor meer informatie over het gebruik met niet-ondersteunde architecturen.

gRPC-aanroeptime-out van HttpClient.Timeout

HttpClient is standaard geconfigureerd met een time-out van 100 seconden. Als een GrpcChannel is geconfigureerd voor het gebruik van een HttpClient, worden langlopende gRPC-streaming-aanroepen geannuleerd als ze niet binnen de time-outlimiet zijn voltooid.

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

Er zijn een aantal manieren om deze fout op te lossen. De eerste is om te configureren HttpClient.Timeout voor een grotere waarde. Timeout.InfiniteTimeSpan schakelt de time-out uit:

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

Vermijd het maken van HttpClient en stel in plaats daarvan GrpcChannel.HttpHandler in.

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

In dit document worden veelvoorkomende problemen besproken bij het ontwikkelen van gRPC-apps op .NET.

Niet-overeenkomende client- en service-SSL/TLS-configuratie

De gRPC-sjabloon en -voorbeelden gebruiken Tls (Transport Layer Security) om gRPC-services standaard te beveiligen. gRPC-clients moeten een beveiligde verbinding gebruiken om beveiligde gRPC-services aan te roepen.

U kunt controleren of de ASP.NET Core gRPC-service TLS gebruikt in de logboeken die zijn geschreven op het begin van de app. De service luistert op een HTTPS-eindpunt:

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

De .NET-client moet https in het serveradres gebruiken om oproepen met een beveiligde verbinding te maken.

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

Alle gRPC-client-implementaties ondersteunen TLS. gRPC-clients uit andere talen vereisen doorgaans het kanaal dat is geconfigureerd met SslCredentials. SslCredentials geeft het certificaat op dat de client gaat gebruiken en moet worden gebruikt in plaats van onveilige referenties. Zie gRPC-verificatie voor voorbeelden van het configureren van de verschillende gRPC-client-implementaties voor het gebruik van TLS.

Een gRPC-service aanroepen met een niet-vertrouwd/ongeldig certificaat

De .NET gRPC-client vereist dat de service een vertrouwd certificaat heeft. Het volgende foutbericht wordt geretourneerd bij het aanroepen van een gRPC-service zonder een vertrouwd certificaat:

Unhandled exception. System.Net.Http.HttpRequestException: de SSL-verbinding kan niet tot stand worden gebracht, zie interne uitzondering. >--- System.Security.Authentication.AuthenticationException: het externe certificaat is ongeldig volgens de validatieprocedure.

Deze fout kan optreden als u uw app lokaal test en het ASP.NET Core HTTPS-ontwikkelingscertificaat niet wordt vertrouwd. Zie Het ASP.NET Core HTTPS-ontwikkelingscertificaat vertrouwen in Windows en macOS voor instructies voor het oplossen van dit probleem.

Als u een gRPC-service aanroept op een andere computer en het certificaat niet kunt vertrouwen, kan de gRPC-client worden geconfigureerd om het ongeldige certificaat te negeren. De volgende code gebruikt HttpClientHandler.ServerCertificateCustomValidationCallback om aanroepen zonder een vertrouwd certificaat toe te staan:

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

De gRPC-clientfactory staat aanroepen toe zonder een vertrouwd certificaat. Gebruik de ConfigurePrimaryHttpMessageHandler extensiemethode om de handler op de client te configureren:

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

        return handler;
    });

Warning

Niet-vertrouwde certificaten mogen alleen worden gebruikt tijdens het ontwikkelen van apps. Productie-apps moeten altijd geldige certificaten gebruiken.

Onveilige gRPC-services aanroepen met .NET-client

De .NET gRPC-client kan onveilige gRPC-services aanroepen door op te geven http in het serveradres. Bijvoorbeeld: GrpcChannel.ForAddress("http://localhost:5000").

Er zijn enkele aanvullende vereisten voor het aanroepen van onveilige gRPC-services, afhankelijk van de .NET-versie die een app gebruikt:

  • Voor .NET 5 of hoger is Grpc.Net.Client versie 2.32.0 of hoger vereist.

  • Voor .NET Core 3.x is extra configuratie vereist. De app moet de System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport schakeloptie instellen op 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);
    

De System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport switch is alleen vereist voor .NET Core 3.x. Het doet niets in .NET 5 en is niet vereist.

Important

Onveilige gRPC-services moeten worden gehost op een HTTP/2-poort. Zie ASP.NET Core-protocolonderhandeling voor meer informatie.

Kan ASP.NET Core gRPC-app niet starten in macOS

Kestrel biedt vóór .NET 8 geen ondersteuning voor HTTP/2 met TLS in macOS. De ASP.NET Core gRPC-sjabloon en voorbeelden maken standaard gebruik van TLS. U ziet het volgende foutbericht wanneer u probeert de gRPC-server te starten:

Kan geen verbinding maken met https://localhost:5001 de IPv4-loopback-interface: 'HTTP/2 via TLS wordt niet ondersteund op macOS vanwege ontbrekende ALPN-ondersteuning.'

Als u dit probleem in .NET 7 of eerder wilt omzeilen, configureert Kestrel u de gRPC-client en gebruikt u HTTP/2 zonder TLS. U moet dit alleen doen tijdens de ontwikkeling. Als u TLS niet gebruikt, worden gRPC-berichten zonder versleuteling verzonden.

Kestrel moet een HTTP/2-eindpunt configureren zonder TLS in 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);
});
  • Vervang in de voorgaande code het localhost-poortnummer 5287 door het HTTP (niet HTTPS) poortnummer dat is opgegeven in Properties/launchSettings.json het gRPC-serviceproject.

Wanneer een HTTP/2-eindpunt is geconfigureerd zonder TLS, moeten de ListenOptions.Protocols van het eindpunt worden ingesteld op HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 kan niet worden gebruikt omdat TLS is vereist om te onderhandelen over HTTP/2. Zonder TLS vallen alle verbindingen met het eindpunt terug op HTTP/1.1, en mislukken gRPC-aanroepen.

De gRPC-client moet ook worden geconfigureerd om TLS niet te gebruiken. Zie Onveilige gRPC-services aanroepen met .NET-client voor meer informatie.

Warning

HTTP/2 zonder TLS mag alleen worden gebruikt tijdens het ontwikkelen van apps. Productie-apps moeten altijd transportbeveiliging gebruiken. Zie Beveiligingsoverwegingen in gRPC voor ASP.NET Core voor meer informatie.

gRPC C#-assets zijn geen code gegenereerd uit .proto bestanden

Voor het genereren van gRPC-code van concrete clients en servicebasisklassen moeten protobuf-bestanden en -hulpprogramma's worden genoemd in een project. U moet het volgende opnemen:

  • .proto bestanden die u wilt gebruiken in de <Protobuf> itemgroep. Er moet naar geïmporteerde .proto bestanden worden verwezen door het project.
  • Pakketverwijzing naar het gRPC-hulpprogrammapakket Grpc.Tools.

Zie gRPC-services met C# voor meer informatie over het genereren van gRPC C#-assets.

Voor een ASP.NET Core-web-app die als host fungeert voor gRPC-services, hoeft alleen de servicebasisklasse te worden gegenereerd:

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

Een gRPC-client-app die gRPC-aanroepen doet, heeft alleen de concrete client nodig die is gegenereerd:

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

WPF-projecten kunnen geen gRPC C#-assets genereren uit .proto bestanden

WPF-projecten hebben een bekend probleem waardoor het genereren van gRPC-code niet correct werkt. Alle gRPC-typen die in een WPF-project worden gegenereerd door te verwijzen naar Grpc.Tools en .proto bestanden, zullen compilatiefouten veroorzaken wanneer ze worden gebruikt.

fout CS0246: Het type of de naamruimtenaam 'MyGrpcServices' is niet gevonden (ontbreekt er een using-instructie of een assemblyreferentie?)

U kunt dit probleem oplossen door:

  1. Maak een nieuw .NET-klassebibliotheekproject.
  2. Voeg in het nieuwe project verwijzingen toe om het genereren van C#-code uit .proto bestanden in te schakelen:
  3. Voeg in de WPF-toepassing een verwijzing toe naar het nieuwe project.

De WPF-toepassing kan gebruikmaken van de gegenereerde gRPC-typen uit het nieuwe klassebibliotheekproject.

GRPC-services aanroepen die worden gehost in een submap

Warning

Veel gRPC-hulpprogramma's van derden bieden geen ondersteuning voor services die worden gehost in submappen. Overweeg om een manier te vinden om gRPC als hoofdmap te hosten.

Het padonderdeel van het adres van een gRPC-kanaal wordt genegeerd bij het plaatsen van gRPC-aanroepen. Wordt bijvoorbeeld GrpcChannel.ForAddress("https://localhost:5001/ignored_path") niet gebruikt bij het routeren van gRPC-aanroepen voor de service ignored_path.

Het adrespad wordt genegeerd omdat gRPC een gestandaardiseerde, prescriptieve adresstructuur heeft. Een gRPC-adres combineert de pakket-, service- en methodenamen: https://localhost:5001/PackageName.ServiceName/MethodName.

Er zijn enkele scenario's waarin een app een pad met gRPC-aanroepen moet bevatten. Wanneer bijvoorbeeld een ASP.NET Core gRPC-app wordt gehost in een IIS-map en de map moet worden opgenomen in de aanvraag. Wanneer een pad is vereist, kan het worden toegevoegd aan de gRPC-aanroep met behulp van de aangepaste SubdirectoryHandler opgegeven hieronder:

/// <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 wordt gebruikt wanneer het gRPC-kanaal wordt gemaakt.

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

De voorgaande code:

  • Hiermee maakt u een SubdirectoryHandler met het pad /MyApp.
  • Hiermee configureert u een kanaal om SubdirectoryHandler te gebruiken.
  • Roept de gRPC-service aan met SayHelloAsync. De gRPC-oproep wordt verzonden naar https://localhost:5001/MyApp/greet.Greeter/SayHello.

U kunt ook een clientfactory configureren met SubdirectoryHandler behulp van AddHttpMessageHandler.

GRPC-client configureren voor het gebruik van HTTP/3

De .NET gRPC-client ondersteunt HTTP/3 met .NET 6 of hoger. Als de server een alt-svc antwoordheader naar de client verzendt die aangeeft dat de server HTTP/3 ondersteunt, wordt de verbinding met HTTP/3 automatisch bijgewerkt. Zie HTTP/3 gebruiken met de ASP.NET Core-webserver Kestrelvoor meer informatie over het inschakelen van HTTP/3 op de server.

HTTP/3-ondersteuning in .NET 8 is standaard ingeschakeld. HTTP/3-ondersteuning in .NET 6 en .NET 7 moet worden ingeschakeld via een configuratievlag in het projectbestand:

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

System.Net.SocketsHttpHandler.Http3Support kan ook worden ingesteld met AppContext.SetSwitch.

A DelegatingHandler kan worden gebruikt om een gRPC-client te dwingen HTTP/3 te gebruiken. Het afdwingen van HTTP/3 voorkomt de overhead van het upgraden van de aanvraag. Forceer HTTP/3 met code die vergelijkbaar is met de volgende:

/// <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 wordt gebruikt wanneer het gRPC-kanaal wordt gemaakt. Met de volgende code wordt een kanaal gemaakt dat is geconfigureerd om Http3Handler te gebruiken.

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

U kunt ook een clientfactory configureren met Http3Handler behulp van AddHttpMessageHandler.

GRPC bouwen in Alpine Linux

Het Grpc.Tools pakket genereert .NET-typen van .proto bestanden met behulp van een gebundeld systeemeigen binair met de naam protoc. Aanvullende stappen zijn vereist voor het bouwen van gRPC-apps op platforms die niet worden ondersteund door de systeemeigen binaire bestanden in Grpc.Tools, zoals Alpine Linux.

Code van tevoren genereren

Een oplossing is om van tevoren code te genereren.

  1. Verplaats .proto bestanden en de Grpc.Tools pakketreferentie naar een nieuw project.
  2. Publiceer het project als een NuGet-pakket en upload het naar een NuGet-feed.
  3. Werk de app bij om te verwijzen naar het NuGet-pakket.

Met de voorgaande stappen hoeft Grpc.Tools de app niet meer te bouwen omdat code van tevoren wordt gegenereerd.

Systeemeigen binaire bestanden aanpassen Grpc.Tools

Grpc.Tools biedt ondersteuning voor het gebruik van aangepaste binaire bestanden. Met deze functie kan de gRPC-tooling worden uitgevoerd in omgevingen waar de geïntegreerde native binaries niet worden ondersteund.

Bouw of verkrijg protoc en grpc_csharp_plugin systeemeigen binaire bestanden en configureer Grpc.Tools om ze te gebruiken. Configureer systeemeigen binaire bestanden door de volgende omgevingsvariabelen in te stellen:

  • PROTOBUF_PROTOC - Volledig pad naar de compiler voor protocolbuffers
  • GRPC_PROTOC_PLUGIN - Volledig pad naar de grpc_csharp_plugin

Voor Alpine Linux zijn er door de community geleverde pakketten voor de protocolbuffers compiler en gRPC-invoegtoepassingen op 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

Zie de Grpc.Tools voor meer informatie over het gebruik met niet-ondersteunde architecturen.

gRPC-aanroeptime-out van HttpClient.Timeout

HttpClient is standaard geconfigureerd met een time-out van 100 seconden. Als een GrpcChannel is geconfigureerd voor het gebruik van een HttpClient, worden langlopende gRPC-streaming-aanroepen geannuleerd als ze niet binnen de time-outlimiet zijn voltooid.

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

Er zijn een aantal manieren om deze fout op te lossen. De eerste is om te configureren HttpClient.Timeout voor een grotere waarde. Timeout.InfiniteTimeSpan schakelt de time-out uit:

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

Vermijd het maken van HttpClient en stel in plaats daarvan GrpcChannel.HttpHandler in.

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

In dit document worden veelvoorkomende problemen besproken bij het ontwikkelen van gRPC-apps op .NET.

Niet-overeenkomende client- en service-SSL/TLS-configuratie

De gRPC-sjabloon en -voorbeelden gebruiken Tls (Transport Layer Security) om gRPC-services standaard te beveiligen. gRPC-clients moeten een beveiligde verbinding gebruiken om beveiligde gRPC-services aan te roepen.

U kunt controleren of de ASP.NET Core gRPC-service TLS gebruikt in de logboeken die zijn geschreven op het begin van de app. De service luistert op een HTTPS-eindpunt:

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

De .NET-client moet https in het serveradres gebruiken om oproepen uit te voeren met een beveiligde verbinding.

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

Alle gRPC-client-implementaties ondersteunen TLS. gRPC-clients uit andere talen vereisen doorgaans het kanaal dat is geconfigureerd met SslCredentials. SslCredentials geeft het certificaat op dat de client gaat gebruiken en moet worden gebruikt in plaats van onveilige referenties. Zie gRPC-verificatie voor voorbeelden van het configureren van de verschillende gRPC-client-implementaties voor het gebruik van TLS.

Een gRPC-service aanroepen met een niet-vertrouwd/ongeldig certificaat

De .NET gRPC-client vereist dat de service een vertrouwd certificaat heeft. Het volgende foutbericht wordt geretourneerd bij het aanroepen van een gRPC-service zonder een vertrouwd certificaat:

Unhandled exception. System.Net.Http.HttpRequestException: de SSL-verbinding kan niet tot stand worden gebracht, zie interne uitzondering. >--- System.Security.Authentication.AuthenticationException: het externe certificaat is ongeldig volgens de validatieprocedure.

Deze fout kan optreden als u uw app lokaal test en het ASP.NET Core HTTPS-ontwikkelingscertificaat niet wordt vertrouwd. Zie Het ASP.NET Core HTTPS-ontwikkelingscertificaat vertrouwen in Windows en macOS voor instructies voor het oplossen van dit probleem.

Als u een gRPC-service aanroept op een andere computer en het certificaat niet kunt vertrouwen, kan de gRPC-client worden geconfigureerd om het ongeldige certificaat te negeren. De volgende code gebruikt HttpClientHandler.ServerCertificateCustomValidationCallback om aanroepen zonder een vertrouwd certificaat toe te staan:

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

De gRPC-clientfactory staat aanroepen toe zonder een vertrouwd certificaat. Gebruik de ConfigurePrimaryHttpMessageHandler extensiemethode om de handler op de client te configureren:

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

        return handler;
    });

Warning

Niet-vertrouwde certificaten mogen alleen worden gebruikt tijdens het ontwikkelen van apps. Productie-apps moeten altijd geldige certificaten gebruiken.

Onveilige gRPC-services aanroepen met .NET-client

De .NET gRPC-client kan onveilige gRPC-services aanroepen door op te geven http in het serveradres. Bijvoorbeeld: GrpcChannel.ForAddress("http://localhost:5000").

Er zijn enkele aanvullende vereisten voor het aanroepen van onveilige gRPC-services, afhankelijk van de .NET-versie die een app gebruikt:

  • Voor .NET 5 of hoger is Grpc.Net.Client versie 2.32.0 of hoger vereist.

  • Voor .NET Core 3.x is extra configuratie vereist. De app moet de System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport schakeloptie instellen op 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);
    

De System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport switch is alleen vereist voor .NET Core 3.x. Het doet niets in .NET 5 en is niet vereist.

Important

Onveilige gRPC-services moeten worden gehost op een HTTP/2-poort. Zie ASP.NET Core-protocolonderhandeling voor meer informatie.

Kan ASP.NET Core gRPC-app niet starten in macOS

Kestrel biedt vóór .NET 8 geen ondersteuning voor HTTP/2 met TLS in macOS. De ASP.NET Core gRPC-sjabloon en voorbeelden maken standaard gebruik van TLS. U ziet het volgende foutbericht wanneer u probeert de gRPC-server te starten:

Kan geen verbinding maken met https://localhost:5001 de IPv4-loopback-interface: 'HTTP/2 via TLS wordt niet ondersteund op macOS vanwege ontbrekende ALPN-ondersteuning.'

Als u dit probleem in .NET 7 of eerder wilt omzeilen, configureert Kestrel u de gRPC-client en gebruikt u HTTP/2 zonder TLS. U moet dit alleen doen tijdens de ontwikkeling. Als u TLS niet gebruikt, worden gRPC-berichten zonder versleuteling verzonden.

Kestrel moet een HTTP/2-eindpunt configureren zonder 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>();
        });

Wanneer een HTTP/2-eindpunt is geconfigureerd zonder TLS, moeten de ListenOptions.Protocols van het eindpunt worden ingesteld op HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 kan niet worden gebruikt omdat TLS is vereist om te onderhandelen over HTTP/2. Zonder TLS vallen alle verbindingen met het eindpunt terug op HTTP/1.1, en mislukken gRPC-aanroepen.

De gRPC-client moet ook worden geconfigureerd om TLS niet te gebruiken. Zie Onveilige gRPC-services aanroepen met .NET-client voor meer informatie.

Warning

HTTP/2 zonder TLS mag alleen worden gebruikt tijdens het ontwikkelen van apps. Productie-apps moeten altijd transportbeveiliging gebruiken. Zie Beveiligingsoverwegingen in gRPC voor ASP.NET Core voor meer informatie.

gRPC C#-assets zijn geen code gegenereerd uit .proto bestanden

Voor het genereren van gRPC-code van concrete clients en servicebasisklassen moeten protobuf-bestanden en -hulpprogramma's worden genoemd in een project. U moet het volgende opnemen:

  • .proto bestanden die u wilt gebruiken in de <Protobuf> itemgroep. Er moet naar geïmporteerde .proto bestanden worden verwezen door het project.
  • Pakketverwijzing naar het gRPC-hulpprogrammapakket Grpc.Tools.

Zie gRPC-services met C# voor meer informatie over het genereren van gRPC C#-assets.

Voor een ASP.NET Core-web-app die als host fungeert voor gRPC-services, hoeft alleen de servicebasisklasse te worden gegenereerd:

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

Een gRPC-client-app die gRPC-aanroepen doet, heeft alleen de concrete client nodig die is gegenereerd:

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

WPF-projecten kunnen geen gRPC C#-assets genereren uit .proto bestanden

WPF-projecten hebben een bekend probleem waardoor het genereren van gRPC-code niet correct werkt. Alle gRPC-typen die in een WPF-project worden gegenereerd door te verwijzen naar Grpc.Tools en .proto bestanden, zullen compilatiefouten veroorzaken wanneer ze worden gebruikt.

fout CS0246: Het type of de naamruimtenaam 'MyGrpcServices' is niet gevonden (ontbreekt er een using-instructie of een assemblyreferentie?)

U kunt dit probleem oplossen door:

  1. Maak een nieuw .NET-klassebibliotheekproject.
  2. Voeg in het nieuwe project verwijzingen toe om het genereren van C#-code uit .proto bestanden in te schakelen:
  3. Voeg in de WPF-toepassing een verwijzing toe naar het nieuwe project.

De WPF-toepassing kan gebruikmaken van de gegenereerde gRPC-typen uit het nieuwe klassebibliotheekproject.

GRPC-services aanroepen die worden gehost in een submap

Warning

Veel gRPC-hulpprogramma's van derden bieden geen ondersteuning voor services die worden gehost in submappen. Overweeg om een manier te vinden om gRPC als hoofdmap te hosten.

Het padonderdeel van het adres van een gRPC-kanaal wordt genegeerd bij het plaatsen van gRPC-aanroepen. Wordt bijvoorbeeld GrpcChannel.ForAddress("https://localhost:5001/ignored_path") niet gebruikt bij het routeren van gRPC-aanroepen voor de service ignored_path.

Het adrespad wordt genegeerd omdat gRPC een gestandaardiseerde, prescriptieve adresstructuur heeft. Een gRPC-adres combineert de pakket-, service- en methodenamen: https://localhost:5001/PackageName.ServiceName/MethodName.

Er zijn enkele scenario's waarin een app een pad met gRPC-aanroepen moet bevatten. Wanneer bijvoorbeeld een ASP.NET Core gRPC-app wordt gehost in een IIS-map en de map moet worden opgenomen in de aanvraag. Wanneer een pad is vereist, kan het worden toegevoegd aan de gRPC-aanroep met behulp van de aangepaste SubdirectoryHandler opgegeven hieronder:

/// <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 wordt gebruikt wanneer het gRPC-kanaal wordt gemaakt.

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

De voorgaande code:

  • Hiermee maakt u een SubdirectoryHandler met het pad /MyApp.
  • Hiermee configureert u een kanaal om SubdirectoryHandler te gebruiken.
  • Roept de gRPC-service aan met SayHelloAsync. De gRPC-oproep wordt verzonden naar https://localhost:5001/MyApp/greet.Greeter/SayHello.

U kunt ook een clientfactory configureren met SubdirectoryHandler behulp van AddHttpMessageHandler.

gRPC-aanroeptime-out van HttpClient.Timeout

HttpClient is standaard geconfigureerd met een time-out van 100 seconden. Als een GrpcChannel is geconfigureerd voor het gebruik van een HttpClient, worden langlopende gRPC-streaming-aanroepen geannuleerd als ze niet binnen de time-outlimiet zijn voltooid.

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

Er zijn een aantal manieren om deze fout op te lossen. De eerste is om te configureren HttpClient.Timeout voor een grotere waarde. Timeout.InfiniteTimeSpan schakelt de time-out uit:

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

Vermijd het maken van HttpClient en stel in plaats daarvan GrpcChannel.HttpHandler in.

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

In dit document worden veelvoorkomende problemen besproken bij het ontwikkelen van gRPC-apps op .NET.

Niet-overeenkomende client- en service-SSL/TLS-configuratie

De gRPC-sjabloon en -voorbeelden gebruiken Tls (Transport Layer Security) om gRPC-services standaard te beveiligen. gRPC-clients moeten een beveiligde verbinding gebruiken om beveiligde gRPC-services aan te roepen.

U kunt controleren of de ASP.NET Core gRPC-service TLS gebruikt in de logboeken die zijn geschreven op het begin van de app. De service luistert op een HTTPS-eindpunt:

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

De .NET-client moet https in het serveradres gebruiken om aanroepen te doen met een beveiligde verbinding.

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

Alle gRPC-client-implementaties ondersteunen TLS. gRPC-clients uit andere talen vereisen doorgaans het kanaal dat is geconfigureerd met SslCredentials. SslCredentials geeft het certificaat op dat de client gaat gebruiken en moet worden gebruikt in plaats van onveilige referenties. Zie gRPC-verificatie voor voorbeelden van het configureren van de verschillende gRPC-client-implementaties voor het gebruik van TLS.

Een gRPC-service aanroepen met een niet-vertrouwd/ongeldig certificaat

De .NET gRPC-client vereist dat de service een vertrouwd certificaat heeft. Het volgende foutbericht wordt geretourneerd bij het aanroepen van een gRPC-service zonder een vertrouwd certificaat:

Unhandled exception. System.Net.Http.HttpRequestException: de SSL-verbinding kan niet tot stand worden gebracht, zie interne uitzondering. >--- System.Security.Authentication.AuthenticationException: het externe certificaat is ongeldig volgens de validatieprocedure.

Deze fout kan optreden als u uw app lokaal test en het ASP.NET Core HTTPS-ontwikkelingscertificaat niet wordt vertrouwd. Zie Het ASP.NET Core HTTPS-ontwikkelingscertificaat vertrouwen in Windows en macOS voor instructies voor het oplossen van dit probleem.

Als u een gRPC-service aanroept op een andere computer en het certificaat niet kunt vertrouwen, kan de gRPC-client worden geconfigureerd om het ongeldige certificaat te negeren. De volgende code gebruikt HttpClientHandler.ServerCertificateCustomValidationCallback om aanroepen zonder een vertrouwd certificaat toe te staan:

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

De gRPC-clientfactory staat aanroepen toe zonder een vertrouwd certificaat. Gebruik de ConfigurePrimaryHttpMessageHandler extensiemethode om de handler op de client te configureren:

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

        return handler;
    });

Warning

Niet-vertrouwde certificaten mogen alleen worden gebruikt tijdens het ontwikkelen van apps. Productie-apps moeten altijd geldige certificaten gebruiken.

Onveilige gRPC-services aanroepen met .NET-client

De .NET gRPC-client kan onveilige gRPC-services aanroepen door op te geven http in het serveradres. Bijvoorbeeld: GrpcChannel.ForAddress("http://localhost:5000").

Er zijn enkele aanvullende vereisten voor het aanroepen van onveilige gRPC-services, afhankelijk van de .NET-versie die een app gebruikt:

  • Voor .NET 5 of hoger is Grpc.Net.Client versie 2.32.0 of hoger vereist.

  • Voor .NET Core 3.x is extra configuratie vereist. De app moet de System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport schakeloptie instellen op 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);
    

De System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport switch is alleen vereist voor .NET Core 3.x. Het doet niets in .NET 5 en is niet vereist.

Important

Onveilige gRPC-services moeten worden gehost op een HTTP/2-poort. Zie ASP.NET Core-protocolonderhandeling voor meer informatie.

Kan ASP.NET Core gRPC-app niet starten in macOS

Kestrel biedt vóór .NET 8 geen ondersteuning voor HTTP/2 met TLS in macOS. De ASP.NET Core gRPC-sjabloon en voorbeelden maken standaard gebruik van TLS. U ziet het volgende foutbericht wanneer u probeert de gRPC-server te starten:

Kan geen verbinding maken met https://localhost:5001 de IPv4-loopback-interface: 'HTTP/2 via TLS wordt niet ondersteund op macOS vanwege ontbrekende ALPN-ondersteuning.'

Als u dit probleem in .NET 7 of eerder wilt omzeilen, configureert Kestrel u de gRPC-client en gebruikt u HTTP/2 zonder TLS. U moet dit alleen doen tijdens de ontwikkeling. Als u TLS niet gebruikt, worden gRPC-berichten zonder versleuteling verzonden.

Kestrel moet een HTTP/2-eindpunt configureren zonder 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>();
        });

Wanneer een HTTP/2-eindpunt is geconfigureerd zonder TLS, moeten de ListenOptions.Protocols van het eindpunt worden ingesteld op HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 kan niet worden gebruikt omdat TLS is vereist om te onderhandelen over HTTP/2. Zonder TLS vallen alle verbindingen met het eindpunt terug op HTTP/1.1, en mislukken gRPC-aanroepen.

De gRPC-client moet ook worden geconfigureerd om TLS niet te gebruiken. Zie Onveilige gRPC-services aanroepen met .NET-client voor meer informatie.

Warning

HTTP/2 zonder TLS mag alleen worden gebruikt tijdens het ontwikkelen van apps. Productie-apps moeten altijd transportbeveiliging gebruiken. Zie Beveiligingsoverwegingen in gRPC voor ASP.NET Core voor meer informatie.

gRPC C#-assets zijn geen code gegenereerd uit .proto bestanden

Voor het genereren van gRPC-code van concrete clients en servicebasisklassen moeten protobuf-bestanden en -hulpprogramma's worden genoemd in een project. U moet het volgende opnemen:

  • .proto bestanden die u wilt gebruiken in de <Protobuf> itemgroep. Er moet naar geïmporteerde .proto bestanden worden verwezen door het project.
  • Pakketverwijzing naar het gRPC-hulpprogrammapakket Grpc.Tools.

Zie gRPC-services met C# voor meer informatie over het genereren van gRPC C#-assets.

Voor een ASP.NET Core-web-app die als host fungeert voor gRPC-services, hoeft alleen de servicebasisklasse te worden gegenereerd:

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

Een gRPC-client-app die gRPC-aanroepen doet, heeft alleen de concrete client nodig die is gegenereerd:

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

WPF-projecten kunnen geen gRPC C#-assets genereren uit .proto bestanden

WPF-projecten hebben een bekend probleem waardoor het genereren van gRPC-code niet correct werkt. Alle gRPC-typen die in een WPF-project worden gegenereerd door te verwijzen naar Grpc.Tools en .proto bestanden, zullen compilatiefouten veroorzaken wanneer ze worden gebruikt.

fout CS0246: Het type of de naamruimtenaam 'MyGrpcServices' is niet gevonden (ontbreekt er een using-instructie of een assemblyreferentie?)

U kunt dit probleem oplossen door:

  1. Maak een nieuw .NET-klassebibliotheekproject.
  2. Voeg in het nieuwe project verwijzingen toe om het genereren van C#-code uit .proto bestanden in te schakelen:
  3. Voeg in de WPF-toepassing een verwijzing toe naar het nieuwe project.

De WPF-toepassing kan gebruikmaken van de gegenereerde gRPC-typen uit het nieuwe klassebibliotheekproject.

GRPC-services aanroepen die worden gehost in een submap

Warning

Veel gRPC-hulpprogramma's van derden bieden geen ondersteuning voor services die worden gehost in submappen. Overweeg om een manier te vinden om gRPC als hoofdmap te hosten.

Het padonderdeel van het adres van een gRPC-kanaal wordt genegeerd bij het plaatsen van gRPC-aanroepen. Wordt bijvoorbeeld GrpcChannel.ForAddress("https://localhost:5001/ignored_path") niet gebruikt bij het routeren van gRPC-aanroepen voor de service ignored_path.

Het adrespad wordt genegeerd omdat gRPC een gestandaardiseerde, prescriptieve adresstructuur heeft. Een gRPC-adres combineert de pakket-, service- en methodenamen: https://localhost:5001/PackageName.ServiceName/MethodName.

Er zijn enkele scenario's waarin een app een pad met gRPC-aanroepen moet bevatten. Wanneer bijvoorbeeld een ASP.NET Core gRPC-app wordt gehost in een IIS-map en de map moet worden opgenomen in de aanvraag. Wanneer een pad is vereist, kan het worden toegevoegd aan de gRPC-aanroep met behulp van de aangepaste SubdirectoryHandler opgegeven hieronder:

/// <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 wordt gebruikt wanneer het gRPC-kanaal wordt gemaakt.

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

De voorgaande code:

  • Hiermee maakt u een SubdirectoryHandler met het pad /MyApp.
  • Hiermee configureert u een kanaal om SubdirectoryHandler te gebruiken.
  • Roept de gRPC-service aan met SayHelloAsync. De gRPC-oproep wordt verzonden naar https://localhost:5001/MyApp/greet.Greeter/SayHello.

U kunt ook een clientfactory configureren met SubdirectoryHandler behulp van AddHttpMessageHandler.

gRPC-aanroeptime-out van HttpClient.Timeout

HttpClient is standaard geconfigureerd met een time-out van 100 seconden. Als een GrpcChannel is geconfigureerd voor het gebruik van een HttpClient, worden langlopende gRPC-streaming-aanroepen geannuleerd als ze niet binnen de time-outlimiet zijn voltooid.

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

Er zijn een aantal manieren om deze fout op te lossen. De eerste is om te configureren HttpClient.Timeout voor een grotere waarde. Timeout.InfiniteTimeSpan schakelt de time-out uit:

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

Vermijd het maken van HttpClient en stel in plaats daarvan GrpcChannel.HttpHandler in.

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