Sdílet prostřednictvím


Průsečíky gRPC v .NET

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální vydání tohoto článku najdete ve verzi .NET 9.

Varování

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální vydání tohoto článku najdete ve verzi .NET 9.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální vydání tohoto článku najdete ve verzi .NET 9.

Autor: Ernst Nguyen

Průsečíky jsou koncept gRPC, který umožňuje aplikacím pracovat s příchozími nebo odchozími voláními gRPC. Nabízejí způsob, jak rozšířit kanál zpracování požadavků.

Průsečíky jsou nakonfigurované pro kanál nebo službu a spouští se automaticky pro každé volání gRPC. Vzhledem k tomu, že zachytávače jsou pro logiku aplikace uživatele transparentní, představují vynikající řešení pro běžné případy, jako je protokolování, monitorování, ověřování a validace.

Typ Interceptor

Zachytávače lze implementovat pro servery gRPC i klienty tím, že vytvoříte třídu, která dědí z typu Interceptor.

public class ExampleInterceptor : Interceptor
{
}

Ve výchozím nastavení Interceptor základní třída nic nedělá. Přidejte chování do zachytávače přepsáním odpovídajících metod základní třídy v implementaci zachytávače.

Klientské interceptory

Zachycovače klienta gRPC zachycují odchozí volání RPC. Poskytují přístup k odeslané žádosti, příchozí odpovědi a kontextu pro volání na straně klienta.

Interceptor metody, které je třeba přepsat pro klienta:

  • BlockingUnaryCall: Zachytí blokující vyvolání unárního RPC.
  • AsyncUnaryCall: Zachycuje asynchronní vyvolání unárního RPC.
  • AsyncClientStreamingCall: Zachytí asynchronní volání RPC klientského streamování.
  • AsyncServerStreamingCall: Zachytí asynchronní vyvolání streamování RPC ze serveru.
  • AsyncDuplexStreamingCall: Zachytí asynchronní vyvolání obousměrného streamování RPC.

Varování

I když obě BlockingUnaryCall a AsyncUnaryCall odkazují na unární rpcs, nejsou zaměnitelné. Blokující vyvolání není zachyceno AsyncUnaryCall a asynchronní vyvolání není zachyceno BlockingUnaryCall.

Vytvoření zachytávání gRPC klienta

Následující kód představuje základní příklad zachycení asynchronního vyvolání unárního volání:

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

Přepsání AsyncUnaryCall:

  • Zachycuje asynchronní unární volání.
  • Zaznamenává podrobnosti o hovoru.
  • Volá parametr předaný continuation do metody. Tím se vyvolá další zachytávač v sérii nebo podkladový volací vyvolávač, pokud se jedná o poslední zachytávač.

Metody na Interceptor pro každý druh metody službou mají různé signatury. Koncept a continuationcontext parametry však zůstávají stejné:

  • continuation je delegát, který vyvolá další interceptor v řetězu nebo základní volací mechanismus (pokud v řetězci nezůstal žádný interceptor). Nejedná se o chybu, která by ji volala nulou nebo vícekrát. Interceptory nejsou povinny vracet reprezentaci volání (AsyncUnaryCall v případě unárního RPC), kterou vrátí delegát continuation. Vynechání volání delegáta a vrácení vaší vlastní instance reprezentace volání přeruší řetězec přerušovačů a okamžitě vrátí přidruženou odpověď.
  • context nese vymezené hodnoty spojené s voláním na straně klienta. Použijte context k předávání metadat, jako jsou bezpečnostní prvky, přihlašovací údaje nebo sledovací data. Kromě toho context přináší informace o konečných termínech a zrušení. Další informace najdete v tématu Spolehlivé služby gRPC s termíny a zrušením.

Čekání na odpověď v zachytávání klienta

Zachytávač může čekat na odpověď v unárních a klientských streamovacích voláních aktualizováním hodnoty AsyncUnaryCall<TResponse>.ResponseAsync nebo 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);
        }
    }
}

Předchozí kód:

  • Vytvoří nový interceptor, který přepisuje AsyncUnaryCall.
  • Přepsání AsyncUnaryCall:
    • Zavolá parametr continuation, který vyvolá další položku v řetězci zachytávače.
    • Vytvoří novou AsyncUnaryCall<TResponse> instanci na základě výsledku pokračování.
    • Zabalí ResponseAsync úlohu pomocí HandleResponse metody.
    • Čeká na odpověď s HandleResponse. Čekání na odpověď umožní přidání logiky po přijetí odpovědi klientem. Čekáním na odpověď v bloku try-catch je možné zaprotokolovat chyby volání.

Další informace o tom, jak vytvořit zachycovač klienta, najdete ClientLoggerInterceptor.cs v příkladu grpc/grpc-dotnet v úložišti GitHub.

Konfigurace klientských interceptorů

Průsečíky klienta gRPC se konfigurují v kanálu.

Následující kód:

  • Vytvoří kanál pomocí GrpcChannel.ForAddress.
  • Intercept Pomocí metody rozšíření nakonfiguruje kanál tak, aby používal průsečík. Všimněte si, že tato metoda vrátí CallInvoker. Silně typovaní klienti gRPC mohou být vytvořeni z invokeru stejně jako z kanálu.
  • Vytvoří klienta z invokeru. Volání gRPC provedená klientem automaticky spustí průsečík.
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var invoker = channel.Intercept(new ClientLoggerInterceptor());

var client = new Greeter.GreeterClient(invoker);

Metodu Intercept rozšíření je možné zřetězit a nakonfigurovat více průsečíků pro kanál. Alternativně existuje Intercept přetížení, které přijímá více průsečíků. Libovolný počet průsečíků lze spustit pro jedno volání gRPC, jak ukazuje následující příklad:

var invoker = channel
    .Intercept(new ClientTokenInterceptor())
    .Intercept(new ClientMonitoringInterceptor())
    .Intercept(new ClientLoggerInterceptor());

Průsečíky se vyvolávají v obráceném pořadí zřetězených Intercept rozšiřujících metod. V předchozím kódu jsou interceptory vyvolány v následujícím pořadí:

  1. ClientLoggerInterceptor
  2. ClientMonitoringInterceptor
  3. ClientTokenInterceptor

Informace o konfiguraci průsečíků s klientskou továrnou gRPC najdete v tématu integrace klientské továrny gRPC v .NET.

Zachytávání serverů

Interceptory serveru gRPC interceptují příchozí požadavky RPC. Poskytují přístup k příchozímu požadavku, odchozí odpovědi a kontextu volání na straně serveru.

Interceptor metody přepsání pro server:

  • UnaryServerHandler: Zachytí unární RPC.
  • ClientStreamingServerHandler: Zachytí rpc streamování klienta.
  • ServerStreamingServerHandler: Zachytí protokol RPC streamování serveru.
  • DuplexStreamingServerHandler: Zachytí obousměrné streamování RPC.

Vytvořte přerušovač gRPC serveru

Následující kód představuje příklad zachycení příchozího unárního RPC:

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

Přepsání UnaryServerHandler:

  • Zachytí příchozí unární hovor.
  • Zaznamenává podrobnosti o hovoru.
  • Volá parametr předaný continuation do metody. Tím se vyvolá další přerušovač v řetězci nebo obslužný modul služby, pokud je toto poslední přerušovač.
  • Zaznamená všechny výjimky. Čekání na pokračování umožní přidání logiky po spuštění metody služby. Čekáním na pokračování v bloku try-catch je možné protokolovat chyby z metod.

Podpis metod průsečíků klienta i serveru je podobný:

  • continuation je zkratka pro delegáta příchozího RPC volání dalšího průsečíku v řetězu nebo obslužné rutině služby (pokud v řetězu není ponechán žádný průsečík). Podobně jako u zachytávačů klienta ji můžete kdykoli zavolat a nemusíte vracet odpověď přímo od delegáta pro pokračování. Odchozí logiku lze přidat po provedení obslužné rutiny služby tím, že vyčkáme na pokračování.
  • context nese metadata spojená s voláním na straně serveru, jako jsou metadata požadavku, termíny a zrušení nebo výsledek RPC.

Další informace o tom, jak vytvořit zachycovač serveru, najdete ServerLoggerInterceptor.cs v příkladu grpc/grpc-dotnet v úložišti GitHub.

Konfigurace serverových interceptorů

Přerušovače serverů gRPC jsou konfigurovány při spuštění. Následující kód:

  • Přidá gRPC do aplikace pomocí AddGrpc.
  • Konfiguruje ServerLoggerInterceptor pro všechny služby tak, že ji přidáte do kolekce možností Interceptors služby.
public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc(options =>
    {
        options.Interceptors.Add<ServerLoggerInterceptor>();
    });
}

Zachytávání lze také nakonfigurovat pro konkrétní službu pomocí AddServiceOptions a určení typu služby.

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddGrpc()
        .AddServiceOptions<GreeterService>(options =>
        {
            options.Interceptors.Add<ServerLoggerInterceptor>();
        });
}

Zachytávače se spouštějí v pořadí, v jakém jsou přidány do InterceptorCollection. Pokud jsou nakonfigurovány jak globální, tak zachytávače pro jednotlivou službu, spustí se nejprve globálně nakonfigurované zachytávače, a teprve poté ty pro jednotlivou službu.

Ve výchozím nastavení mají průsečíky serverů gRPC životnost podle požadavku. Přepsání tohoto chování je možné prostřednictvím registrace typu interceptor pomocí injekce závislostí. Následující příklad zaregistruje životnost jednohotonu ServerLoggerInterceptor :

public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc(options =>
    {
        options.Interceptors.Add<ServerLoggerInterceptor>();
    });

    services.AddSingleton<ServerLoggerInterceptor>();
}

Zachytávače gRPC versus middleware

ASP.NET middleware Core nabízí podobné funkce v porovnání s průsečíky v aplikacích GRPC založených na jádru C. Middleware a zachytávače v ASP.NET Core jsou koncepčně podobné. Oba:

  • Slouží k vytvoření potrubí, které zpracovává požadavek gRPC.
  • Povolte provedení práce před nebo po další komponentě v procesním řetězci.
  • Poskytnout přístup k HttpContext:
    • V middlewaru je parametr HttpContext .
    • U zachytávačů HttpContext lze přistupovat pomocí parametru ServerCallContext s rozšiřovací metodou ServerCallContext.GetHttpContext. Tato funkce je specifická pro průsečíky spuštěné v ASP.NET Core.

Rozdíly průsečíku gRPC od middlewaru ASP.NET Core:

  • Průsečíky:
    • Pracovat s gRPC vrstvy abstrakce pomocí ServerCallContext.
    • Poskytnutí přístupu k:
      • Deserializovaná zpráva byla odeslána volání.
      • Zpráva vrácená z volání předtím, než byla serializována.
    • Dokáže zachytit a zpracovat výjimky vyvolané službami gRPC.
  • Middleware:
    • Spustí se pro všechny požadavky HTTP.
    • Spustí se před průsečíky gRPC.
    • Pracuje s podkladovými zprávami HTTP/2.
    • Může přistupovat pouze k bajtům z datových proudů požadavků a odpovědí.

Další materiály