Intercettori 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.
Gli intercettori sono un concetto gRPC che consente alle app di interagire con le chiamate gRPC in ingresso o in uscita. Offrono un modo per arricchire la pipeline di elaborazione delle richieste.
Gli intercettori sono configurati per un canale o un servizio ed eseguiti automaticamente per ogni chiamata gRPC. Poiché gli intercettori sono trasparenti per la logica dell'applicazione dell'utente, sono una soluzione eccellente per i casi comuni, ad esempio registrazione, monitoraggio, autenticazione e convalida.
Tipo diInterceptor
Gli intercettori possono essere implementati sia per i server gRPC che per i client creando una classe che eredita dal Interceptor
tipo :
public class ExampleInterceptor : Interceptor
{
}
Per impostazione predefinita, la Interceptor
classe base non esegue alcuna operazione. Aggiungere il comportamento a un intercettore eseguendo l'override dei metodi della classe di base appropriati in un'implementazione dell'intercettore.
Intercettori client
Gli intercettori client gRPC intercettano le chiamate RPC in uscita. Forniscono l'accesso alla richiesta inviata, alla risposta in ingresso e al contesto per una chiamata lato client.
Interceptor
metodi di override per il client:
BlockingUnaryCall
: intercetta una chiamata di blocco di una RPC unaria.AsyncUnaryCall
: intercetta una chiamata asincrona di una RPC unaria.AsyncClientStreamingCall
: intercetta una chiamata asincrona di una RPC di streaming client.AsyncServerStreamingCall
: intercetta una chiamata asincrona di una RPC in streaming server.AsyncDuplexStreamingCall
: intercetta una chiamata asincrona di una RPC di streaming bidirezionale.
Avviso
Anche se entrambi BlockingUnaryCall
e AsyncUnaryCall
fanno riferimento a RPC unari, non sono intercambiabili. Una chiamata di blocco non viene intercettata da AsyncUnaryCall
e una chiamata asincrona non viene intercettata da un oggetto BlockingUnaryCall
.
Creare un intercettore gRPC client
Il codice seguente presenta un esempio di base dell'intercettazione di una chiamata asincrona di una chiamata unaria:
public class ClientLoggingInterceptor : Interceptor
{
private readonly ILogger _logger;
public ClientLoggingInterceptor(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<ClientLoggingInterceptor>();
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
_logger.LogInformation("Starting call. Type/Method: {Type} / {Method}",
context.Method.Type, context.Method.Name);
return continuation(request, context);
}
}
Override di AsyncUnaryCall
:
- Intercetta una chiamata unaria asincrona.
- Registra informazioni dettagliate sulla chiamata.
- Chiama il
continuation
parametro passato al metodo . In questo modo viene richiamato l'intercettore successivo nella catena o il chiamante sottostante se si tratta dell'ultimo intercettore.
I metodi su Interceptor
per ogni tipo di metodo di servizio hanno firme diverse. Tuttavia, il concetto alla base continuation
dei parametri e context
rimane invariato:
continuation
è un delegato che richiama l'intercettore successivo nella catena o il chiamante sottostante (se nella catena non è rimasto alcun intercettore). Non è un errore chiamarlo zero o più volte. Gli intercettori non devono restituire una rappresentazione di chiamata (AsyncUnaryCall
in caso di RPC unario) restituita dalcontinuation
delegato. Omettendo la chiamata del delegato e restituendo la propria istanza della rappresentazione di chiamata, la catena degli intercettori viene interrotta e viene restituita immediatamente la risposta associata.context
contiene valori con ambito associati alla chiamata sul lato client. Usarecontext
per passare metadati, ad esempio entità di sicurezza, credenziali o dati di traccia. Inoltre,context
contiene informazioni sulle scadenze e l'annullamento. Per altre informazioni, vedere Reliable gRPC services with deadline and cancellation .For more information, see Reliable gRPC services with deadline and cancellation.
Attesa della risposta nell'intercettore client
Un intercettore può attendere la risposta nelle chiamate di streaming unario e client aggiornando il AsyncUnaryCall<TResponse>.ResponseAsync
valore o AsyncClientStreamingCall<TRequest, TResponse>.ResponseAsync
.
public class ErrorHandlerInterceptor : Interceptor
{
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var call = continuation(request, context);
return new AsyncUnaryCall<TResponse>(
HandleResponse(call.ResponseAsync),
call.ResponseHeadersAsync,
call.GetStatus,
call.GetTrailers,
call.Dispose);
}
private async Task<TResponse> HandleResponse<TResponse>(Task<TResponse> inner)
{
try
{
return await inner;
}
catch (Exception ex)
{
throw new InvalidOperationException("Custom error", ex);
}
}
}
Il codice precedente:
- Crea un nuovo intercettore che esegue l'override
AsyncUnaryCall
di . - Override di
AsyncUnaryCall
:- Chiama il
continuation
parametro per richiamare l'elemento successivo nella catena dell'intercettore. - Crea una nuova
AsyncUnaryCall<TResponse>
istanza in base al risultato della continuazione. - Esegue il wrapping dell'attività
ResponseAsync
usando ilHandleResponse
metodo . - Attende la risposta con
HandleResponse
. In attesa della risposta è possibile aggiungere la logica dopo che il client ha ricevuto la risposta. Attendendo la risposta in un blocco try-catch, è possibile registrare gli errori delle chiamate.
- Chiama il
Per altre informazioni su come creare un intercettore client, vedere l'esempio ClientLoggerInterceptor.cs
nel grpc/grpc-dotnet
repository GitHub.
Configurare gli intercettori client
Gli intercettori client gRPC sono configurati in un canale.
Il codice seguente:
- Crea un canale usando
GrpcChannel.ForAddress
. - Usa il
Intercept
metodo di estensione per configurare il canale per l'uso dell'intercettore. Si noti che questo metodo restituisce un oggettoCallInvoker
. I client gRPC fortemente tipizzato possono essere creati da un invoker proprio come un canale. - Crea un client dal invoker. Chiamate gRPC effettuate dal client eseguono automaticamente l'intercettore.
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var invoker = channel.Intercept(new ClientLoggerInterceptor());
var client = new Greeter.GreeterClient(invoker);
Il Intercept
metodo di estensione può essere concatenato per configurare più intercettori per un canale. In alternativa, è presente un Intercept
overload che accetta più intercettori. È possibile eseguire un numero qualsiasi di intercettori per una singola chiamata gRPC, come illustrato nell'esempio seguente:
var invoker = channel
.Intercept(new ClientTokenInterceptor())
.Intercept(new ClientMonitoringInterceptor())
.Intercept(new ClientLoggerInterceptor());
Gli intercettori vengono richiamati in ordine inverso dei metodi di estensione concatenati Intercept
. Nel codice precedente, gli intercettori vengono richiamati nell'ordine seguente:
ClientLoggerInterceptor
ClientMonitoringInterceptor
ClientTokenInterceptor
Per informazioni su come configurare gli intercettori con la factory client gRPC, vedere integrazione della factory client gRPC in .NET.
Intercettori server
Gli intercettori del server gRPC intercettano le richieste RPC in ingresso. Forniscono l'accesso alla richiesta in ingresso, alla risposta in uscita e al contesto per una chiamata lato server.
Interceptor
metodi di override per il server:
UnaryServerHandler
: intercetta unario RPC.ClientStreamingServerHandler
: intercetta una RPC in streaming client.ServerStreamingServerHandler
: intercetta una RPC in streaming server.DuplexStreamingServerHandler
: intercetta una RPC bidirezionale in streaming.
Creare un intercettore gRPC del server
Il codice seguente presenta un esempio di intercettazione di una RPC unaria in ingresso:
public class ServerLoggerInterceptor : Interceptor
{
private readonly ILogger _logger;
public ServerLoggerInterceptor(ILogger<ServerLoggerInterceptor> logger)
{
_logger = logger;
}
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
_logger.LogInformation("Starting receiving call. Type/Method: {Type} / {Method}",
MethodType.Unary, context.Method);
try
{
return await continuation(request, context);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error thrown by {context.Method}.");
throw;
}
}
}
Override di UnaryServerHandler
:
- Intercetta una chiamata unaria in ingresso.
- Registra informazioni dettagliate sulla chiamata.
- Chiama il
continuation
parametro passato al metodo . In questo modo viene richiamato l'intercettore successivo nella catena o nel gestore del servizio se si tratta dell'ultimo intercettore. - Registra eventuali eccezioni. In attesa della continuazione è possibile aggiungere la logica dopo l'esecuzione del metodo del servizio. Attendendo la continuazione in un blocco try-catch, è possibile registrare gli errori dei metodi.
La firma dei metodi di intercettore client e server è simile:
continuation
indica un delegato per un RPC in ingresso che chiama l'intercettore successivo nella catena o il gestore del servizio (se nella catena non è presente alcun intercettore). Analogamente agli intercettori client, è possibile chiamarla in qualsiasi momento e non è necessario restituire una risposta direttamente dal delegato di continuazione. La logica in uscita può essere aggiunta dopo l'esecuzione di un gestore del servizio in attesa della continuazione.context
contiene metadati associati alla chiamata sul lato server, ad esempio metadati della richiesta, scadenze e annullamento o risultato RPC.
Per altre informazioni su come creare un intercettore server, vedere l'esempio ServerLoggerInterceptor.cs
nel grpc/grpc-dotnet
repository GitHub.
Configurare gli intercettori del server
Gli intercettori del server gRPC vengono configurati all'avvio. Il codice seguente:
- Aggiunge gRPC all'app con
AddGrpc
. ServerLoggerInterceptor
Configura per tutti i servizi aggiungendolo alla raccolta dell'opzione diInterceptors
servizio.
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc(options =>
{
options.Interceptors.Add<ServerLoggerInterceptor>();
});
}
È anche possibile configurare un intercettore per un servizio specifico usando AddServiceOptions
e specificando il tipo di servizio.
public void ConfigureServices(IServiceCollection services)
{
services
.AddGrpc()
.AddServiceOptions<GreeterService>(options =>
{
options.Interceptors.Add<ServerLoggerInterceptor>();
});
}
Gli intercettori vengono eseguiti nell'ordine in cui vengono aggiunti a InterceptorCollection
. Se sono configurati intercettori globali e singoli, gli intercettori configurati a livello globale vengono eseguiti prima di quelli configurati per un singolo servizio.
Per impostazione predefinita, gli intercettori del server gRPC hanno una durata per richiesta. L'override di questo comportamento è possibile tramite la registrazione del tipo di intercettore con inserimento delle dipendenze. L'esempio seguente registra l'oggetto ServerLoggerInterceptor
con una durata singleton:
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc(options =>
{
options.Interceptors.Add<ServerLoggerInterceptor>();
});
services.AddSingleton<ServerLoggerInterceptor>();
}
Intercettori gRPC e middleware
ASP.NET middleware Core offre funzionalità simili rispetto agli intercettori nelle app gRPC basate su C core. ASP.NET middleware core e gli intercettori sono concettualmente simili. Entrambe le opzioni:
- Vengono usati per costruire una pipeline che gestisce una richiesta gRPC.
- Consentire l'esecuzione del lavoro prima o dopo il componente successivo nella pipeline.
- Fornire l'accesso a
HttpContext
:- Nel middleware, è
HttpContext
un parametro . - Negli intercettori è
HttpContext
possibile accedere a utilizzando ilServerCallContext
parametro con il metodo diServerCallContext.GetHttpContext
estensione. Questa funzionalità è specifica per gli intercettori in esecuzione in ASP.NET Core.
- Nel middleware, è
Differenze tra l'intercettore gRPC e il middleware core ASP.NET:
- Intercettori:
- Operare sul livello gRPC dell'astrazione usando .
ServerCallContext
- Fornire l'accesso a:
- Messaggio deserializzato inviato a una chiamata.
- Messaggio restituito dalla chiamata prima della serializzazione.
- Può intercettare e gestire le eccezioni generate dai servizi gRPC.
- Operare sul livello gRPC dell'astrazione usando .
- Middleware:
- Viene eseguito per tutte le richieste HTTP.
- Viene eseguito prima degli intercettori gRPC.
- Opera sui messaggi HTTP/2 sottostanti.
- Può accedere solo ai byte dai flussi di richiesta e risposta.