Risolvere i problemi di gRPC in .NET
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:
- .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
sutrue
. Per altre informazioni, vedere Asp.Net Core 3.x: Chiamare servizi gRPC non sicuri con il client .NET:
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:
- Creare un nuovo progetto di libreria di classi .NET Core.
- Nel nuovo progetto aggiungere riferimenti per abilitare la generazione di codice C# dai
.proto
file:- Aggiungere i riferimenti al pacchetto seguenti:
- Aggiungere i file
.proto
al gruppo di elementi<Protobuf>
.
- 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 ahttps://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.
- Spostare
.proto
i file e il riferimento alGrpc.Tools
pacchetto a un nuovo progetto. - Pubblicare il progetto come pacchetto NuGet e caricarlo in un feed NuGet.
- 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 protocolloGRPC_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 HttpClient
oggetto , 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
sutrue
:// 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 ilHTTP
numero di porta (nonHTTPS
) specificato nelProperties/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:
- Creare un nuovo progetto di libreria di classi .NET Core.
- Nel nuovo progetto aggiungere riferimenti per abilitare la generazione di codice C# dai
.proto
file:- Aggiungere i riferimenti al pacchetto seguenti:
- Aggiungere i file
.proto
al gruppo di elementi<Protobuf>
.
- 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 ahttps://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.
- Spostare
.proto
i file e il riferimento alGrpc.Tools
pacchetto a un nuovo progetto. - Pubblicare il progetto come pacchetto NuGet e caricarlo in un feed NuGet.
- 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 protocolloGRPC_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 HttpClient
oggetto , 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
sutrue
:// 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:
- Creare un nuovo progetto di libreria di classi .NET Core.
- Nel nuovo progetto aggiungere riferimenti per abilitare la generazione di codice C# dai
.proto
file:- Aggiungere i riferimenti al pacchetto seguenti:
- Aggiungere i file
.proto
al gruppo di elementi<Protobuf>
.
- 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 ahttps://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 HttpClient
oggetto , 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
sutrue
:// 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:
- Creare un nuovo progetto di libreria di classi .NET Core.
- Nel nuovo progetto aggiungere riferimenti per abilitare la generazione di codice C# dai
.proto
file:- Aggiungere i riferimenti al pacchetto seguenti:
- Aggiungere i file
.proto
al gruppo di elementi<Protobuf>
.
- 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 ahttps://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 HttpClient
oggetto , 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);