Risolvere i problemi di gRPC in .NET

Di James Newton-King

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Questo documento illustra i problemi comunemente riscontrati durante lo sviluppo di app gRPC in .NET.

Mancata corrispondenza tra la configurazione SSL/TLS del client e del servizio

Il modello e gli esempi gRPC usano Transport Layer Security (TLS) per proteggere i servizi gRPC per impostazione predefinita. I client gRPC devono usare una connessione sicura per chiamare correttamente i servizi gRPC protetti.

È possibile verificare che il servizio ASP.NET Core gRPC usi TLS nei log scritti all'avvio dell'app. Il servizio sarà in ascolto su un endpoint 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

Il client .NET Core deve usare https nell'indirizzo del server per effettuare chiamate con una connessione protetta:

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

Tutte le implementazioni del client gRPC supportano TLS. I client gRPC provenienti da altre lingue richiedono in genere il canale configurato con SslCredentials. SslCredentials specifica il certificato che verrà usato dal client e deve essere usato invece di credenziali non sicure. Per esempi di configurazione delle diverse implementazioni del client gRPC per l'uso di TLS, vedere Autenticazione gRPC.

Chiamare un servizio gRPC con un certificato non attendibile/non valido

Il client .NET gRPC richiede che il servizio disponga di un certificato attendibile. Quando si chiama un servizio gRPC senza un certificato attendibile, viene restituito il messaggio di errore seguente:

Eccezione non gestita. System.Net.Http.HttpRequestException: impossibile stabilire la connessione SSL, vedere l'eccezione interna. >--- System.Security.Authentication.AuthenticationException: il certificato remoto non è valido in base alla procedura di convalida.

Questo errore può verificarsi se si sta testando l'app in locale e il certificato di sviluppo HTTPS core ASP.NET non è attendibile. Per istruzioni su come risolvere questo problema, vedere Considerare attendibile il certificato di sviluppo di ASP.NET Core HTTPS in Windows e macOS.

Se si chiama un servizio gRPC in un altro computer e non è possibile considerare attendibile il certificato, il client gRPC può essere configurato per ignorare il certificato non valido. Il codice seguente usa HttpClientHandler.ServerCertificateCustomValidationCallback per consentire le chiamate senza un certificato attendibile:

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

La factory client gRPC consente chiamate senza un certificato attendibile. Usare il ConfigurePrimaryHttpMessageHandler metodo di estensione per configurare il gestore nel client:


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

Avviso

I certificati non attendibili devono essere usati solo durante lo sviluppo di app. Le app di produzione devono sempre usare certificati validi.

Chiamare servizi gRPC non sicuri con il client .NET Core

Il client .NET gRPC può chiamare servizi gRPC non sicuri specificando http l'indirizzo del server. Ad esempio: GrpcChannel.ForAddress("http://localhost:5000").

Esistono alcuni requisiti aggiuntivi per chiamare servizi gRPC non sicuri a seconda della versione .NET usata da un'app:

Importante

I servizi gRPC non sicuri devono essere ospitati in una porta solo HTTP/2. Per altre informazioni, vedere ASP.NET negoziazione del protocollo Core.

Impossibile avviare ASP.NET'app Core gRPC in macOS

Kestrel non supporta HTTP/2 con TLS in macOS prima di .NET 8. Il modello ASP.NET Core gRPC e gli esempi usano TLS per impostazione predefinita. Quando si tenta di avviare il server gRPC, verrà visualizzato il messaggio di errore seguente:

Impossibile eseguire l'associazione a https://localhost:5001 nell'interfaccia di loopback IPv4: "HTTP/2 su TLS non è supportato in macOS a causa del supporto ALPN mancante".

Per risolvere questo problema in .NET 7 e versioni precedenti, configurare Kestrel e il client gRPC per usare HTTP/2 senza TLS. Questa operazione deve essere eseguita solo durante lo sviluppo. L'uso di TLS comporta l'invio di messaggi gRPC senza crittografia. Per altre informazioni, vedere Asp.Net Core 7.0: Impossibile avviare ASP.NET'app Core gRPC in macOS.

Gli asset C# gRPC non vengono generati da .proto file

La generazione di codice gRPC di client concreti e classi di base del servizio richiede file protobuf e strumenti a cui fare riferimento da un progetto. È necessario includere:

  • .proto file che si desidera utilizzare nel <Protobuf> gruppo di elementi. I file importati .proto devono fare riferimento al progetto.
  • Riferimento al pacchetto gRPC tooling Grpc.Tools.

Per altre informazioni sulla generazione di asset GRPC C#, vedere gRPC services with C#.

Un'app Web ASP.NET Core che ospita i servizi gRPC richiede solo la classe di base del servizio generata:

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

Un'app client gRPC che effettua chiamate gRPC richiede solo il client concreto generato:

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

I progetti WPF non sono in grado di generare asset C# gRPC da .proto file

I progetti WPF presentano un problema noto che impedisce il corretto funzionamento della generazione del codice gRPC. Tutti i tipi gRPC generati in un progetto WPF facendo riferimento ai file e .proto creeranno errori di compilazione Grpc.Tools quando vengono usati:

errore CS0246: Impossibile trovare il tipo o il nome dello spazio dei nomi 'MyGrpcServices' (manca una direttiva using o un riferimento all'assembly?)

Per risolvere questo problema, è possibile:

  1. Creare un nuovo progetto di libreria di classi .NET Core.
  2. Nel nuovo progetto aggiungere riferimenti per abilitare la generazione di codice C# dai .proto file:
  3. Nell'applicazione WPF aggiungere un riferimento al nuovo progetto.

L'applicazione WPF può usare i tipi generati da gRPC dal nuovo progetto di libreria di classi.

Chiamata di servizi gRPC ospitati in una sottodirectory

Avviso

Molti strumenti gRPC di terze parti non supportano i servizi ospitati nelle sottodirectory. Valutare la possibilità di trovare un modo per ospitare gRPC come directory radice.

Il componente del percorso dell'indirizzo di un canale gRPC viene ignorato durante l'esecuzione di chiamate gRPC. Ad esempio, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") non verrà usato ignored_path quando si instradano chiamate gRPC per il servizio.

Il percorso dell'indirizzo viene ignorato perché gRPC ha una struttura di indirizzi prescrittiva standardizzata. Un indirizzo gRPC combina il pacchetto, il servizio e i nomi dei metodi: https://localhost:5001/PackageName.ServiceName/MethodName.

Esistono alcuni scenari in cui un'app deve includere un percorso con chiamate gRPC. Ad esempio, quando un'app ASP.NET Core gRPC è ospitata in una directory IIS e la directory deve essere inclusa nella richiesta. Quando è necessario un percorso, può essere aggiunto alla chiamata gRPC usando l'opzione personalizzata SubdirectoryHandler specificata di seguito:

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 viene usato quando viene creato il canale 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" });

Il codice precedente:

  • Crea un SubdirectoryHandler oggetto con il percorso /MyApp.
  • Configura un canale per l'uso di SubdirectoryHandler.
  • Chiama il servizio gRPC con SayHelloAsync. La chiamata gRPC viene inviata a https://localhost:5001/MyApp/greet.Greeter/SayHello.

In alternativa, una factory client può essere configurata con SubdirectoryHandler usando AddHttpMessageHandler.

Configurare il client gRPC per l'uso di HTTP/3

Il client .NET gRPC supporta HTTP/3 con .NET 6 o versione successiva. Se il server invia un'intestazione alt-svc di risposta al client che indica che il server supporta HTTP/3, il client aggiornerà automaticamente la connessione a HTTP/3. Per altre informazioni, vedere Usare HTTP/3 con il server Web ASP.NET CoreKestrel.

Un DelegatingHandler oggetto può essere usato per forzare l'uso di HTTP/3 da parte di un client gRPC. L'uso forzato di HTTP/3 evita il sovraccarico dell'aggiornamento della richiesta. Forzare HTTP/3 con codice simile al seguente:

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 viene usato quando viene creato il canale gRPC. Il codice seguente crea un canale configurato per l'uso di 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" });

In alternativa, una factory client può essere configurata con Http3Handler usando AddHttpMessageHandler.

Compilazione di gRPC in Alpine Linux

Il Grpc.Tools pacchetto genera tipi .NET dai .proto file usando un file binario nativo in bundle denominato protoc. Sono necessari passaggi aggiuntivi per compilare app gRPC su piattaforme non supportate dai file binari nativi in Grpc.Tools, ad esempio Alpine Linux.

Generare codice in anticipo

Una soluzione consiste nel generare codice in anticipo.

  1. Spostare .proto i file e il riferimento al Grpc.Tools pacchetto a un nuovo progetto.
  2. Pubblicare il progetto come pacchetto NuGet e caricarlo in un feed NuGet.
  3. Aggiornare l'app per fare riferimento al pacchetto NuGet.

Con i passaggi precedenti, l'app non richiede Grpc.Tools più la compilazione perché il codice viene generato in anticipo.

Personalizzare Grpc.Tools i file binari nativi

Grpc.Tools supporta l'uso di file binari nativi personalizzati. Questa funzionalità consente l'esecuzione degli strumenti gRPC negli ambienti in cui i file binari nativi in bundle non supportano.

Compilare o acquisire protoc file grpc_csharp_plugin binari nativi e configurarli Grpc.Tools per usarli. Configurare i file binari nativi impostando le variabili di ambiente seguenti:

  • PROTOBUF_PROTOC - Percorso completo del compilatore di buffer del protocollo
  • GRPC_PROTOC_PLUGIN - Percorso completo del grpc_csharp_plugin

Per Alpine Linux, sono disponibili pacchetti forniti dalla community per il compilatore di buffer del protocollo e i plug-in gRPC all'indirizzo 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

Per altre informazioni sull'uso Grpc.Tools di con architetture non supportate, vedere la documentazione sull'integrazione della compilazione gRPC.

timeout di chiamata gRPC da HttpClient.Timeout

HttpClient è configurato con un timeout di 100 secondi per impostazione predefinita. Se un GrpcChannel oggetto è configurato per l'uso di un HttpClientoggetto , le chiamate di streaming gRPC a esecuzione prolungata vengono annullate se non vengono completate entro il limite di timeout.

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

Esistono due modi per correggere l'errore. Il primo consiste nel configurare HttpClient.Timeout un valore maggiore. Timeout.InfiniteTimeSpan disabilita il timeout:

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

In alternativa, evitare di creare HttpClient e impostare 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);

Questo documento illustra i problemi comunemente riscontrati durante lo sviluppo di app gRPC in .NET.

Mancata corrispondenza tra la configurazione SSL/TLS del client e del servizio

Il modello e gli esempi gRPC usano Transport Layer Security (TLS) per proteggere i servizi gRPC per impostazione predefinita. I client gRPC devono usare una connessione sicura per chiamare correttamente i servizi gRPC protetti.

È possibile verificare che il servizio ASP.NET Core gRPC usi TLS nei log scritti all'avvio dell'app. Il servizio sarà in ascolto su un endpoint 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

Il client .NET Core deve usare https nell'indirizzo del server per effettuare chiamate con una connessione protetta:

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

Tutte le implementazioni del client gRPC supportano TLS. I client gRPC provenienti da altre lingue richiedono in genere il canale configurato con SslCredentials. SslCredentials specifica il certificato che verrà usato dal client e deve essere usato invece di credenziali non sicure. Per esempi di configurazione delle diverse implementazioni del client gRPC per l'uso di TLS, vedere Autenticazione gRPC.

Chiamare un servizio gRPC con un certificato non attendibile/non valido

Il client .NET gRPC richiede che il servizio disponga di un certificato attendibile. Quando si chiama un servizio gRPC senza un certificato attendibile, viene restituito il messaggio di errore seguente:

Eccezione non gestita. System.Net.Http.HttpRequestException: impossibile stabilire la connessione SSL, vedere l'eccezione interna. >--- System.Security.Authentication.AuthenticationException: il certificato remoto non è valido in base alla procedura di convalida.

Questo errore può verificarsi se si sta testando l'app in locale e il certificato di sviluppo HTTPS core ASP.NET non è attendibile. Per istruzioni su come risolvere questo problema, vedere Considerare attendibile il certificato di sviluppo di ASP.NET Core HTTPS in Windows e macOS.

Se si chiama un servizio gRPC in un altro computer e non è possibile considerare attendibile il certificato, il client gRPC può essere configurato per ignorare il certificato non valido. Il codice seguente usa HttpClientHandler.ServerCertificateCustomValidationCallback per consentire le chiamate senza un certificato attendibile:

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

La factory client gRPC consente chiamate senza un certificato attendibile. Usare il ConfigurePrimaryHttpMessageHandler metodo di estensione per configurare il gestore nel client:

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

        return handler;
    });

Avviso

I certificati non attendibili devono essere usati solo durante lo sviluppo di app. Le app di produzione devono sempre usare certificati validi.

Chiamare servizi gRPC non sicuri con il client .NET Core

Il client .NET gRPC può chiamare servizi gRPC non sicuri specificando http l'indirizzo del server. Ad esempio: GrpcChannel.ForAddress("http://localhost:5000").

Esistono alcuni requisiti aggiuntivi per chiamare servizi gRPC non sicuri a seconda della versione .NET usata da un'app:

  • .NET 5 o versione successiva richiede Grpc.Net.Client versione 2.32.0 o successiva.

  • .NET Core 3.x richiede una configurazione aggiuntiva. L'app deve impostare l'opzione System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport su 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);
    

L'opzione System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport è necessaria solo per .NET Core 3.x. Non esegue alcuna operazione in .NET 5 e non è necessaria.

Importante

I servizi gRPC non sicuri devono essere ospitati in una porta solo HTTP/2. Per altre informazioni, vedere ASP.NET negoziazione del protocollo Core.

Impossibile avviare ASP.NET'app Core gRPC in macOS

Kestrel non supporta HTTP/2 con TLS in macOS prima di .NET 8. Il modello ASP.NET Core gRPC e gli esempi usano TLS per impostazione predefinita. Quando si tenta di avviare il server gRPC, verrà visualizzato il messaggio di errore seguente:

Impossibile eseguire l'associazione a https://localhost:5001 nell'interfaccia di loopback IPv4: "HTTP/2 su TLS non è supportato in macOS a causa del supporto ALPN mancante".

Per risolvere questo problema in .NET 7 e versioni precedenti, configurare Kestrel e il client gRPC per usare HTTP/2 senza TLS. Questa operazione deve essere eseguita solo durante lo sviluppo. L'uso di TLS comporta l'invio di messaggi gRPC senza crittografia.

Kestrel deve configurare un endpoint HTTP/2 senza 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);
});
  • Nel codice precedente sostituire il numero 5287 di porta localhost con il HTTP numero di porta (non HTTPS) specificato nel Properties/launchSettings.json progetto di servizio gRPC.

Quando un endpoint HTTP/2 è configurato senza TLS, l'endpoint ListenOptions.Protocols deve essere impostato su HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 non può essere usato perché TLS è necessario per negoziare HTTP/2. Senza TLS, tutte le connessioni all'endpoint sono predefinite HTTP/1.1 e le chiamate gRPC hanno esito negativo.

Il client gRPC deve anche essere configurato per non usare TLS. Per altre informazioni, vedere Chiamare servizi gRPC non sicuri con il client .NET Core.

Avviso

HTTP/2 senza TLS deve essere usato solo durante lo sviluppo di app. Le app di produzione devono sempre usare la sicurezza del trasporto. Per altre informazioni, vedere Considerazioni sulla sicurezza in gRPC per ASP.NET Core.

Gli asset C# gRPC non vengono generati da .proto file

La generazione di codice gRPC di client concreti e classi di base del servizio richiede file protobuf e strumenti a cui fare riferimento da un progetto. È necessario includere:

  • .proto file che si desidera utilizzare nel <Protobuf> gruppo di elementi. I file importati .proto devono fare riferimento al progetto.
  • Riferimento al pacchetto gRPC tooling Grpc.Tools.

Per altre informazioni sulla generazione di asset GRPC C#, vedere gRPC services with C#.

Un'app Web ASP.NET Core che ospita i servizi gRPC richiede solo la classe di base del servizio generata:

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

Un'app client gRPC che effettua chiamate gRPC richiede solo il client concreto generato:

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

I progetti WPF non sono in grado di generare asset C# gRPC da .proto file

I progetti WPF presentano un problema noto che impedisce il corretto funzionamento della generazione del codice gRPC. Tutti i tipi gRPC generati in un progetto WPF facendo riferimento ai file e .proto creeranno errori di compilazione Grpc.Tools quando vengono usati:

errore CS0246: Impossibile trovare il tipo o il nome dello spazio dei nomi 'MyGrpcServices' (manca una direttiva using o un riferimento all'assembly?)

Per risolvere questo problema, è possibile:

  1. Creare un nuovo progetto di libreria di classi .NET Core.
  2. Nel nuovo progetto aggiungere riferimenti per abilitare la generazione di codice C# dai .proto file:
  3. Nell'applicazione WPF aggiungere un riferimento al nuovo progetto.

L'applicazione WPF può usare i tipi generati da gRPC dal nuovo progetto di libreria di classi.

Chiamata di servizi gRPC ospitati in una sottodirectory

Avviso

Molti strumenti gRPC di terze parti non supportano i servizi ospitati nelle sottodirectory. Valutare la possibilità di trovare un modo per ospitare gRPC come directory radice.

Il componente del percorso dell'indirizzo di un canale gRPC viene ignorato durante l'esecuzione di chiamate gRPC. Ad esempio, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") non verrà usato ignored_path quando si instradano chiamate gRPC per il servizio.

Il percorso dell'indirizzo viene ignorato perché gRPC ha una struttura di indirizzi prescrittiva standardizzata. Un indirizzo gRPC combina il pacchetto, il servizio e i nomi dei metodi: https://localhost:5001/PackageName.ServiceName/MethodName.

Esistono alcuni scenari in cui un'app deve includere un percorso con chiamate gRPC. Ad esempio, quando un'app ASP.NET Core gRPC è ospitata in una directory IIS e la directory deve essere inclusa nella richiesta. Quando è necessario un percorso, può essere aggiunto alla chiamata gRPC usando l'opzione personalizzata SubdirectoryHandler specificata di seguito:

/// <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 viene usato quando viene creato il canale 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" });

Il codice precedente:

  • Crea un SubdirectoryHandler oggetto con il percorso /MyApp.
  • Configura un canale per l'uso di SubdirectoryHandler.
  • Chiama il servizio gRPC con SayHelloAsync. La chiamata gRPC viene inviata a https://localhost:5001/MyApp/greet.Greeter/SayHello.

In alternativa, una factory client può essere configurata con SubdirectoryHandler usando AddHttpMessageHandler.

Configurare il client gRPC per l'uso di HTTP/3

Il client .NET gRPC supporta HTTP/3 con .NET 6 o versione successiva. Se il server invia un'intestazione alt-svc di risposta al client che indica che il server supporta HTTP/3, il client aggiornerà automaticamente la connessione a HTTP/3. Per informazioni su come abilitare HTTP/3 nel server, vedere Usare HTTP/3 con il server Web ASP.NET CoreKestrel.

Il supporto HTTP/3 in .NET 8 è abilitato per impostazione predefinita. Il supporto HTTP/3 in .NET 6 e .NET 7 deve essere abilitato tramite un flag di configurazione nel file di progetto:

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

System.Net.SocketsHttpHandler.Http3Support può anche essere impostato usando AppContext.SetSwitch.

Un DelegatingHandler oggetto può essere usato per forzare l'uso di HTTP/3 da parte di un client gRPC. L'uso forzato di HTTP/3 evita il sovraccarico dell'aggiornamento della richiesta. Forzare HTTP/3 con codice simile al seguente:

/// <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 viene usato quando viene creato il canale gRPC. Il codice seguente crea un canale configurato per l'uso di 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" });

In alternativa, una factory client può essere configurata con Http3Handler usando AddHttpMessageHandler.

Compilazione di gRPC in Alpine Linux

Il Grpc.Tools pacchetto genera tipi .NET dai .proto file usando un file binario nativo in bundle denominato protoc. Sono necessari passaggi aggiuntivi per compilare app gRPC su piattaforme non supportate dai file binari nativi in Grpc.Tools, ad esempio Alpine Linux.

Generare codice in anticipo

Una soluzione consiste nel generare codice in anticipo.

  1. Spostare .proto i file e il riferimento al Grpc.Tools pacchetto a un nuovo progetto.
  2. Pubblicare il progetto come pacchetto NuGet e caricarlo in un feed NuGet.
  3. Aggiornare l'app per fare riferimento al pacchetto NuGet.

Con i passaggi precedenti, l'app non richiede Grpc.Tools più la compilazione perché il codice viene generato in anticipo.

Personalizzare Grpc.Tools i file binari nativi

Grpc.Tools supporta l'uso di file binari nativi personalizzati. Questa funzionalità consente l'esecuzione degli strumenti gRPC negli ambienti in cui i file binari nativi in bundle non supportano.

Compilare o acquisire protoc file grpc_csharp_plugin binari nativi e configurarli Grpc.Tools per usarli. Configurare i file binari nativi impostando le variabili di ambiente seguenti:

  • PROTOBUF_PROTOC - Percorso completo del compilatore di buffer del protocollo
  • GRPC_PROTOC_PLUGIN - Percorso completo del grpc_csharp_plugin

Per Alpine Linux, sono disponibili pacchetti forniti dalla community per il compilatore di buffer del protocollo e i plug-in gRPC all'indirizzo 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

Per altre informazioni sull'uso Grpc.Tools di con architetture non supportate, vedere la documentazione sull'integrazione della compilazione gRPC.

timeout di chiamata gRPC da HttpClient.Timeout

HttpClient è configurato con un timeout di 100 secondi per impostazione predefinita. Se un GrpcChannel oggetto è configurato per l'uso di un HttpClientoggetto , le chiamate di streaming gRPC a esecuzione prolungata vengono annullate se non vengono completate entro il limite di timeout.

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

Esistono due modi per correggere l'errore. Il primo consiste nel configurare HttpClient.Timeout un valore maggiore. Timeout.InfiniteTimeSpan disabilita il timeout:

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

In alternativa, evitare di creare HttpClient e impostare 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);

Questo documento illustra i problemi comunemente riscontrati durante lo sviluppo di app gRPC in .NET.

Mancata corrispondenza tra la configurazione SSL/TLS del client e del servizio

Il modello e gli esempi gRPC usano Transport Layer Security (TLS) per proteggere i servizi gRPC per impostazione predefinita. I client gRPC devono usare una connessione sicura per chiamare correttamente i servizi gRPC protetti.

È possibile verificare che il servizio ASP.NET Core gRPC usi TLS nei log scritti all'avvio dell'app. Il servizio sarà in ascolto su un endpoint 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

Il client .NET Core deve usare https nell'indirizzo del server per effettuare chiamate con una connessione protetta:

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

Tutte le implementazioni del client gRPC supportano TLS. I client gRPC provenienti da altre lingue richiedono in genere il canale configurato con SslCredentials. SslCredentials specifica il certificato che verrà usato dal client e deve essere usato invece di credenziali non sicure. Per esempi di configurazione delle diverse implementazioni del client gRPC per l'uso di TLS, vedere Autenticazione gRPC.

Chiamare un servizio gRPC con un certificato non attendibile/non valido

Il client .NET gRPC richiede che il servizio disponga di un certificato attendibile. Quando si chiama un servizio gRPC senza un certificato attendibile, viene restituito il messaggio di errore seguente:

Eccezione non gestita. System.Net.Http.HttpRequestException: impossibile stabilire la connessione SSL, vedere l'eccezione interna. >--- System.Security.Authentication.AuthenticationException: il certificato remoto non è valido in base alla procedura di convalida.

Questo errore può verificarsi se si sta testando l'app in locale e il certificato di sviluppo HTTPS core ASP.NET non è attendibile. Per istruzioni su come risolvere questo problema, vedere Considerare attendibile il certificato di sviluppo di ASP.NET Core HTTPS in Windows e macOS.

Se si chiama un servizio gRPC in un altro computer e non è possibile considerare attendibile il certificato, il client gRPC può essere configurato per ignorare il certificato non valido. Il codice seguente usa HttpClientHandler.ServerCertificateCustomValidationCallback per consentire le chiamate senza un certificato attendibile:

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

La factory client gRPC consente chiamate senza un certificato attendibile. Usare il ConfigurePrimaryHttpMessageHandler metodo di estensione per configurare il gestore nel client:

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

        return handler;
    });

Avviso

I certificati non attendibili devono essere usati solo durante lo sviluppo di app. Le app di produzione devono sempre usare certificati validi.

Chiamare servizi gRPC non sicuri con il client .NET Core

Il client .NET gRPC può chiamare servizi gRPC non sicuri specificando http l'indirizzo del server. Ad esempio: GrpcChannel.ForAddress("http://localhost:5000").

Esistono alcuni requisiti aggiuntivi per chiamare servizi gRPC non sicuri a seconda della versione .NET usata da un'app:

  • .NET 5 o versione successiva richiede Grpc.Net.Client versione 2.32.0 o successiva.

  • .NET Core 3.x richiede una configurazione aggiuntiva. L'app deve impostare l'opzione System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport su 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);
    

L'opzione System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport è necessaria solo per .NET Core 3.x. Non esegue alcuna operazione in .NET 5 e non è necessaria.

Importante

I servizi gRPC non sicuri devono essere ospitati in una porta solo HTTP/2. Per altre informazioni, vedere ASP.NET negoziazione del protocollo Core.

Impossibile avviare ASP.NET'app Core gRPC in macOS

Kestrel non supporta HTTP/2 con TLS in macOS prima di .NET 8. Il modello ASP.NET Core gRPC e gli esempi usano TLS per impostazione predefinita. Quando si tenta di avviare il server gRPC, verrà visualizzato il messaggio di errore seguente:

Impossibile eseguire l'associazione a https://localhost:5001 nell'interfaccia di loopback IPv4: "HTTP/2 su TLS non è supportato in macOS a causa del supporto ALPN mancante".

Per risolvere questo problema in .NET 7 e versioni precedenti, configurare Kestrel e il client gRPC per usare HTTP/2 senza TLS. Questa operazione deve essere eseguita solo durante lo sviluppo. L'uso di TLS comporta l'invio di messaggi gRPC senza crittografia.

Kestrel deve configurare un endpoint HTTP/2 senza 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>();
        });

Quando un endpoint HTTP/2 è configurato senza TLS, l'endpoint ListenOptions.Protocols deve essere impostato su HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 non può essere usato perché TLS è necessario per negoziare HTTP/2. Senza TLS, tutte le connessioni all'endpoint sono predefinite HTTP/1.1 e le chiamate gRPC hanno esito negativo.

Il client gRPC deve anche essere configurato per non usare TLS. Per altre informazioni, vedere Chiamare servizi gRPC non sicuri con il client .NET Core.

Avviso

HTTP/2 senza TLS deve essere usato solo durante lo sviluppo di app. Le app di produzione devono sempre usare la sicurezza del trasporto. Per altre informazioni, vedere Considerazioni sulla sicurezza in gRPC per ASP.NET Core.

Gli asset C# gRPC non vengono generati da .proto file

La generazione di codice gRPC di client concreti e classi di base del servizio richiede file protobuf e strumenti a cui fare riferimento da un progetto. È necessario includere:

  • .proto file che si desidera utilizzare nel <Protobuf> gruppo di elementi. I file importati .proto devono fare riferimento al progetto.
  • Riferimento al pacchetto gRPC tooling Grpc.Tools.

Per altre informazioni sulla generazione di asset GRPC C#, vedere gRPC services with C#.

Un'app Web ASP.NET Core che ospita i servizi gRPC richiede solo la classe di base del servizio generata:

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

Un'app client gRPC che effettua chiamate gRPC richiede solo il client concreto generato:

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

I progetti WPF non sono in grado di generare asset C# gRPC da .proto file

I progetti WPF presentano un problema noto che impedisce il corretto funzionamento della generazione del codice gRPC. Tutti i tipi gRPC generati in un progetto WPF facendo riferimento ai file e .proto creeranno errori di compilazione Grpc.Tools quando vengono usati:

errore CS0246: Impossibile trovare il tipo o il nome dello spazio dei nomi 'MyGrpcServices' (manca una direttiva using o un riferimento all'assembly?)

Per risolvere questo problema, è possibile:

  1. Creare un nuovo progetto di libreria di classi .NET Core.
  2. Nel nuovo progetto aggiungere riferimenti per abilitare la generazione di codice C# dai .proto file:
  3. Nell'applicazione WPF aggiungere un riferimento al nuovo progetto.

L'applicazione WPF può usare i tipi generati da gRPC dal nuovo progetto di libreria di classi.

Chiamata di servizi gRPC ospitati in una sottodirectory

Avviso

Molti strumenti gRPC di terze parti non supportano i servizi ospitati nelle sottodirectory. Valutare la possibilità di trovare un modo per ospitare gRPC come directory radice.

Il componente del percorso dell'indirizzo di un canale gRPC viene ignorato durante l'esecuzione di chiamate gRPC. Ad esempio, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") non verrà usato ignored_path quando si instradano chiamate gRPC per il servizio.

Il percorso dell'indirizzo viene ignorato perché gRPC ha una struttura di indirizzi prescrittiva standardizzata. Un indirizzo gRPC combina il pacchetto, il servizio e i nomi dei metodi: https://localhost:5001/PackageName.ServiceName/MethodName.

Esistono alcuni scenari in cui un'app deve includere un percorso con chiamate gRPC. Ad esempio, quando un'app ASP.NET Core gRPC è ospitata in una directory IIS e la directory deve essere inclusa nella richiesta. Quando è necessario un percorso, può essere aggiunto alla chiamata gRPC usando l'opzione personalizzata SubdirectoryHandler specificata di seguito:

/// <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 viene usato quando viene creato il canale 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" });

Il codice precedente:

  • Crea un SubdirectoryHandler oggetto con il percorso /MyApp.
  • Configura un canale per l'uso di SubdirectoryHandler.
  • Chiama il servizio gRPC con SayHelloAsync. La chiamata gRPC viene inviata a https://localhost:5001/MyApp/greet.Greeter/SayHello.

In alternativa, una factory client può essere configurata con SubdirectoryHandler usando AddHttpMessageHandler.

timeout di chiamata gRPC da HttpClient.Timeout

HttpClient è configurato con un timeout di 100 secondi per impostazione predefinita. Se un GrpcChannel oggetto è configurato per l'uso di un HttpClientoggetto , le chiamate di streaming gRPC a esecuzione prolungata vengono annullate se non vengono completate entro il limite di timeout.

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

Esistono due modi per correggere l'errore. Il primo consiste nel configurare HttpClient.Timeout un valore maggiore. Timeout.InfiniteTimeSpan disabilita il timeout:

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

In alternativa, evitare di creare HttpClient e impostare 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);

Questo documento illustra i problemi comunemente riscontrati durante lo sviluppo di app gRPC in .NET.

Mancata corrispondenza tra la configurazione SSL/TLS del client e del servizio

Il modello e gli esempi gRPC usano Transport Layer Security (TLS) per proteggere i servizi gRPC per impostazione predefinita. I client gRPC devono usare una connessione sicura per chiamare correttamente i servizi gRPC protetti.

È possibile verificare che il servizio ASP.NET Core gRPC usi TLS nei log scritti all'avvio dell'app. Il servizio sarà in ascolto su un endpoint 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

Il client .NET Core deve usare https nell'indirizzo del server per effettuare chiamate con una connessione protetta:

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

Tutte le implementazioni del client gRPC supportano TLS. I client gRPC provenienti da altre lingue richiedono in genere il canale configurato con SslCredentials. SslCredentials specifica il certificato che verrà usato dal client e deve essere usato invece di credenziali non sicure. Per esempi di configurazione delle diverse implementazioni del client gRPC per l'uso di TLS, vedere Autenticazione gRPC.

Chiamare un servizio gRPC con un certificato non attendibile/non valido

Il client .NET gRPC richiede che il servizio disponga di un certificato attendibile. Quando si chiama un servizio gRPC senza un certificato attendibile, viene restituito il messaggio di errore seguente:

Eccezione non gestita. System.Net.Http.HttpRequestException: impossibile stabilire la connessione SSL, vedere l'eccezione interna. >--- System.Security.Authentication.AuthenticationException: il certificato remoto non è valido in base alla procedura di convalida.

Questo errore può verificarsi se si sta testando l'app in locale e il certificato di sviluppo HTTPS core ASP.NET non è attendibile. Per istruzioni su come risolvere questo problema, vedere Considerare attendibile il certificato di sviluppo di ASP.NET Core HTTPS in Windows e macOS.

Se si chiama un servizio gRPC in un altro computer e non è possibile considerare attendibile il certificato, il client gRPC può essere configurato per ignorare il certificato non valido. Il codice seguente usa HttpClientHandler.ServerCertificateCustomValidationCallback per consentire le chiamate senza un certificato attendibile:

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

La factory client gRPC consente chiamate senza un certificato attendibile. Usare il ConfigurePrimaryHttpMessageHandler metodo di estensione per configurare il gestore nel client:

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

        return handler;
    });

Avviso

I certificati non attendibili devono essere usati solo durante lo sviluppo di app. Le app di produzione devono sempre usare certificati validi.

Chiamare servizi gRPC non sicuri con il client .NET Core

Il client .NET gRPC può chiamare servizi gRPC non sicuri specificando http l'indirizzo del server. Ad esempio: GrpcChannel.ForAddress("http://localhost:5000").

Esistono alcuni requisiti aggiuntivi per chiamare servizi gRPC non sicuri a seconda della versione .NET usata da un'app:

  • .NET 5 o versione successiva richiede Grpc.Net.Client versione 2.32.0 o successiva.

  • .NET Core 3.x richiede una configurazione aggiuntiva. L'app deve impostare l'opzione System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport su 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);
    

L'opzione System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport è necessaria solo per .NET Core 3.x. Non esegue alcuna operazione in .NET 5 e non è necessaria.

Importante

I servizi gRPC non sicuri devono essere ospitati in una porta solo HTTP/2. Per altre informazioni, vedere ASP.NET negoziazione del protocollo Core.

Impossibile avviare ASP.NET'app Core gRPC in macOS

Kestrel non supporta HTTP/2 con TLS in macOS prima di .NET 8. Il modello ASP.NET Core gRPC e gli esempi usano TLS per impostazione predefinita. Quando si tenta di avviare il server gRPC, verrà visualizzato il messaggio di errore seguente:

Impossibile eseguire l'associazione a https://localhost:5001 nell'interfaccia di loopback IPv4: "HTTP/2 su TLS non è supportato in macOS a causa del supporto ALPN mancante".

Per risolvere questo problema in .NET 7 e versioni precedenti, configurare Kestrel e il client gRPC per usare HTTP/2 senza TLS. Questa operazione deve essere eseguita solo durante lo sviluppo. L'uso di TLS comporta l'invio di messaggi gRPC senza crittografia.

Kestrel deve configurare un endpoint HTTP/2 senza 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>();
        });

Quando un endpoint HTTP/2 è configurato senza TLS, l'endpoint ListenOptions.Protocols deve essere impostato su HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 non può essere usato perché TLS è necessario per negoziare HTTP/2. Senza TLS, tutte le connessioni all'endpoint sono predefinite HTTP/1.1 e le chiamate gRPC hanno esito negativo.

Il client gRPC deve anche essere configurato per non usare TLS. Per altre informazioni, vedere Chiamare servizi gRPC non sicuri con il client .NET Core.

Avviso

HTTP/2 senza TLS deve essere usato solo durante lo sviluppo di app. Le app di produzione devono sempre usare la sicurezza del trasporto. Per altre informazioni, vedere Considerazioni sulla sicurezza in gRPC per ASP.NET Core.

Gli asset C# gRPC non vengono generati da .proto file

La generazione di codice gRPC di client concreti e classi di base del servizio richiede file protobuf e strumenti a cui fare riferimento da un progetto. È necessario includere:

  • .proto file che si desidera utilizzare nel <Protobuf> gruppo di elementi. I file importati .proto devono fare riferimento al progetto.
  • Riferimento al pacchetto gRPC tooling Grpc.Tools.

Per altre informazioni sulla generazione di asset GRPC C#, vedere gRPC services with C#.

Un'app Web ASP.NET Core che ospita i servizi gRPC richiede solo la classe di base del servizio generata:

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

Un'app client gRPC che effettua chiamate gRPC richiede solo il client concreto generato:

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

I progetti WPF non sono in grado di generare asset C# gRPC da .proto file

I progetti WPF presentano un problema noto che impedisce il corretto funzionamento della generazione del codice gRPC. Tutti i tipi gRPC generati in un progetto WPF facendo riferimento ai file e .proto creeranno errori di compilazione Grpc.Tools quando vengono usati:

errore CS0246: Impossibile trovare il tipo o il nome dello spazio dei nomi 'MyGrpcServices' (manca una direttiva using o un riferimento all'assembly?)

Per risolvere questo problema, è possibile:

  1. Creare un nuovo progetto di libreria di classi .NET Core.
  2. Nel nuovo progetto aggiungere riferimenti per abilitare la generazione di codice C# dai .proto file:
  3. Nell'applicazione WPF aggiungere un riferimento al nuovo progetto.

L'applicazione WPF può usare i tipi generati da gRPC dal nuovo progetto di libreria di classi.

Chiamata di servizi gRPC ospitati in una sottodirectory

Avviso

Molti strumenti gRPC di terze parti non supportano i servizi ospitati nelle sottodirectory. Valutare la possibilità di trovare un modo per ospitare gRPC come directory radice.

Il componente del percorso dell'indirizzo di un canale gRPC viene ignorato durante l'esecuzione di chiamate gRPC. Ad esempio, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") non verrà usato ignored_path quando si instradano chiamate gRPC per il servizio.

Il percorso dell'indirizzo viene ignorato perché gRPC ha una struttura di indirizzi prescrittiva standardizzata. Un indirizzo gRPC combina il pacchetto, il servizio e i nomi dei metodi: https://localhost:5001/PackageName.ServiceName/MethodName.

Esistono alcuni scenari in cui un'app deve includere un percorso con chiamate gRPC. Ad esempio, quando un'app ASP.NET Core gRPC è ospitata in una directory IIS e la directory deve essere inclusa nella richiesta. Quando è necessario un percorso, può essere aggiunto alla chiamata gRPC usando l'opzione personalizzata SubdirectoryHandler specificata di seguito:

/// <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 viene usato quando viene creato il canale 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" });

Il codice precedente:

  • Crea un SubdirectoryHandler oggetto con il percorso /MyApp.
  • Configura un canale per l'uso di SubdirectoryHandler.
  • Chiama il servizio gRPC con SayHelloAsync. La chiamata gRPC viene inviata a https://localhost:5001/MyApp/greet.Greeter/SayHello.

In alternativa, una factory client può essere configurata con SubdirectoryHandler usando AddHttpMessageHandler.

timeout di chiamata gRPC da HttpClient.Timeout

HttpClient è configurato con un timeout di 100 secondi per impostazione predefinita. Se un GrpcChannel oggetto è configurato per l'uso di un HttpClientoggetto , le chiamate di streaming gRPC a esecuzione prolungata vengono annullate se non vengono completate entro il limite di timeout.

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

Esistono due modi per correggere l'errore. Il primo consiste nel configurare HttpClient.Timeout un valore maggiore. Timeout.InfiniteTimeSpan disabilita il timeout:

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

In alternativa, evitare di creare HttpClient e impostare 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);