Udostępnij za pośrednictwem


przechwytywanie gRPC na platformie .NET

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Przez Ernest Nguyen

Przechwytywanie to koncepcja gRPC, która umożliwia aplikacjom interakcję z przychodzącymi lub wychodzącymi wywołaniami gRPC. Oferują one sposób wzbogacania potoku przetwarzania żądań.

Przechwytniki są konfigurowane dla kanału lub usługi i wykonywane automatycznie dla każdego wywołania gRPC. Ponieważ przechwytywanie jest niewidoczne dla logiki aplikacji użytkownika, jest doskonałym rozwiązaniem dla typowych przypadków, takich jak rejestrowanie, monitorowanie, uwierzytelnianie i walidacja.

Typ: Interceptor

Przechwytywanie można zaimplementować zarówno dla serwerów gRPC, jak i klientów, tworząc klasę dziedziczą po typie Interceptor :

public class ExampleInterceptor : Interceptor
{
}

Domyślnie klasa bazowa Interceptor nic nie robi. Dodaj zachowanie do przechwytywania, przesłaniając odpowiednie metody klasy bazowej w implementacji przechwytywania.

Przechwytniki klienta

przechwytujące przechwytniki klienta gRPC przechwytujące wychodzące wywołania RPC. Zapewniają one dostęp do wysłanego żądania, odpowiedzi przychodzącej i kontekstu wywołania po stronie klienta.

Interceptor metody zastąpienia dla klienta:

  • BlockingUnaryCall: przechwytuje blokowanie wywołania jednoargumentowego wywołania RPC.
  • AsyncUnaryCall: przechwytuje asynchroniczne wywołanie jednoargumentowego wywołania RPC.
  • AsyncClientStreamingCall: przechwytuje asynchroniczne wywołanie wywołania RPC przesyłania strumieniowego klienta.
  • AsyncServerStreamingCall: przechwytuje asynchroniczne wywołanie wywołania RPC przesyłania strumieniowego serwera.
  • AsyncDuplexStreamingCall: przechwytuje asynchroniczne wywołanie dwukierunkowego przesyłania strumieniowego RPC.

Ostrzeżenie

Mimo że obie BlockingUnaryCall metody i AsyncUnaryCall odwołują się do jednoargumentowych kontrolerów RPC, nie są one wymienne. Wywołanie blokujące nie jest przechwytywane przez AsyncUnaryCallelement , a wywołanie asynchroniczne nie jest przechwytywane przez BlockingUnaryCallelement .

Tworzenie przechwytywania gRPC klienta

Poniższy kod przedstawia podstawowy przykład przechwytywania asynchronicznego wywołania jednoargumentowego:

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

Zastępowanie AsyncUnaryCall:

  • Przechwytuje asynchroniczne jednoargumentowe wywołanie.
  • Rejestruje szczegółowe informacje o wywołaniu.
  • continuation Wywołuje parametr przekazany do metody . Spowoduje to wywołanie następnego przechwytywania w łańcuchu lub wywołania bazowego, jeśli jest to ostatni przechwytnik.

Metody dla Interceptor każdego rodzaju metody usługi mają różne sygnatury. Jednak koncepcja i continuation context parametry pozostają takie same:

  • continuation jest delegatem, który wywołuje następny przechwytnik w łańcuchu lub źródłowy wywołanie wywołania (jeśli w łańcuchu nie ma przechwytywania). Nie jest to błąd, aby wywołać go zero lub wiele razy. Przechwytywanie nie jest wymagane do zwrócenia reprezentacji wywołania (AsyncUnaryCall w przypadku jednoargumentowego wywołania RPC) zwróconego z delegata continuation . Pominięcie wywołania delegata i zwrócenie własnego wystąpienia reprezentacji wywołania powoduje przerwanie łańcucha przechwytujących i natychmiastowe zwrócenie skojarzonej odpowiedzi.
  • context program przenosi wartości o określonym zakresie skojarzone z wywołaniem po stronie klienta. Służy context do przekazywania metadanych, takich jak podmioty zabezpieczeń, poświadczenia lub dane śledzenia. Ponadto prowadzi context informacje o terminach ostatecznych i anulowaniu. Aby uzyskać więcej informacji, zobacz Reliable gRPC services with deadline and cancellation (Niezawodne usługi gRPC z terminami i anulowaniem).

Oczekiwanie na odpowiedź w przechwytywaniu klienta

Przechwytywanie może oczekiwać na odpowiedź w wywołaniach jednoargumentowych i przesyłania strumieniowego klienta przez zaktualizowanie AsyncUnaryCall<TResponse>.ResponseAsync wartości lub 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);
        }
    }
}

Powyższy kod ma następujące działanie:

  • Tworzy nowy przechwytujący, który zastępuje AsyncUnaryCallelement .
  • Zastępowanie AsyncUnaryCall:
    • Wywołuje parametr , continuation aby wywołać następny element w łańcuchu przechwytywania.
    • Tworzy nowe AsyncUnaryCall<TResponse> wystąpienie na podstawie wyniku kontynuacji.
    • Opakowuje ResponseAsync zadanie przy użyciu HandleResponse metody .
    • Oczekuje na odpowiedź za pomocą polecenia HandleResponse. Oczekiwanie na odpowiedź umożliwia dodanie logiki po otrzymaniu odpowiedzi przez klienta. Oczekując na odpowiedź w bloku try-catch, można rejestrować błędy z wywołań.

Aby uzyskać więcej informacji na temat tworzenia przechwytywania klienta, zobacz ClientLoggerInterceptor.cs przykład w grpc/grpc-dotnet repozytorium GitHub.

Konfigurowanie przechwytywania klientów

Przechwytywanie klientów gRPC jest konfigurowane w kanale.

Następujący kod powoduje:

  • Tworzy kanał przy użyciu polecenia GrpcChannel.ForAddress.
  • Intercept Używa metody rozszerzenia do skonfigurowania kanału do używania przechwytywania. Należy pamiętać, że ta metoda zwraca wartość CallInvoker. Silnie typizowanych klientów gRPC można tworzyć na podstawie wywołania, podobnie jak kanał.
  • Tworzy klienta z wywołania. Wywołania gRPC wykonywane przez klienta automatycznie wykonują przechwytywanie.
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var invoker = channel.Intercept(new ClientLoggerInterceptor());

var client = new Greeter.GreeterClient(invoker);

Intercept Metodę rozszerzenia można połączyć w łańcuch, aby skonfigurować wiele przechwytujących dla kanału. Alternatywnie istnieje Intercept przeciążenie, które akceptuje wiele przechwytujących. W przypadku pojedynczego wywołania gRPC można wykonać dowolną liczbę przechwytywania, jak pokazano w poniższym przykładzie:

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

Przechwytniki są wywoływane w odwrotnej kolejności metod rozszerzeń łańcuchowych Intercept . W poprzednim kodzie przechwytujące są wywoływane w następującej kolejności:

  1. ClientLoggerInterceptor
  2. ClientMonitoringInterceptor
  3. ClientTokenInterceptor

Aby uzyskać informacje na temat konfigurowania przechwytywania za pomocą fabryki klienta gRPC, zobacz integracja fabryki klienta gRPC na platformie .NET.

Przechwytniki serwera

przechwytatory serwera gRPC przechwytywać przychodzące żądania RPC. Zapewniają one dostęp do żądania przychodzącego, odpowiedzi wychodzącej i kontekstu wywołania po stronie serwera.

Interceptor metody przesłaniania dla serwera:

  • UnaryServerHandler: przechwytuje jednoargumentowy RPC.
  • ClientStreamingServerHandler: przechwytuje RPC przesyłania strumieniowego klienta.
  • ServerStreamingServerHandler: przechwytuje RPC przesyłania strumieniowego serwera.
  • DuplexStreamingServerHandler: przechwytuje dwukierunkowe przesyłanie strumieniowe RPC.

Tworzenie przechwytywania gRPC serwera

Poniższy kod przedstawia przykład przechwycenia przychodzącego jednoargumentowego 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;
        }
    }
}

Zastępowanie UnaryServerHandler:

  • Przechwytuje przychodzące jednoargumentowe wywołanie.
  • Rejestruje szczegółowe informacje o wywołaniu.
  • continuation Wywołuje parametr przekazany do metody . Spowoduje to wywołanie następnego przechwytnika w łańcuchu lub procedurę obsługi usługi, jeśli jest to ostatni przechwytujący.
  • Rejestruje wszelkie wyjątki. Oczekiwanie na kontynuację umożliwia dodanie logiki po wykonaniu metody usługi. Oczekując na kontynuację w bloku try-catch, błędy z metod można rejestrować.

Podpis metod przechwytywania klienta i serwera jest podobny:

  • continuation oznacza delegata dla przychodzącego RPC wywołującego następny przechwytywanie w łańcuchu lub program obsługi usługi (jeśli w łańcuchu nie ma przechwytnika). Podobnie jak w przypadku przechwytywania klienta, można go wywołać w dowolnym momencie i nie ma potrzeby zwracania odpowiedzi bezpośrednio z delegata kontynuacji. Logikę ruchu wychodzącego można dodać po wykonaniu programu obsługi usługi przez oczekiwanie na kontynuację.
  • context przenosi metadane skojarzone z wywołaniem po stronie serwera, takie jak metadane żądania, terminy i anulowanie lub wynik wywołania procedury RPC.

Aby uzyskać więcej informacji na temat tworzenia przechwytywania serwera, zobacz ServerLoggerInterceptor.cs przykład w grpc/grpc-dotnet repozytorium GitHub.

Konfigurowanie przechwytywania serwerów

Przechwytniki serwera gRPC są konfigurowane podczas uruchamiania. Następujący kod powoduje:

  • Dodaje gRPC do aplikacji za pomocą polecenia AddGrpc.
  • Konfiguruje ServerLoggerInterceptor wszystkie usługi przez dodanie jej do kolekcji Interceptors opcji usługi.
public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc(options =>
    {
        options.Interceptors.Add<ServerLoggerInterceptor>();
    });
}

Przechwytnika można również skonfigurować dla określonej usługi przy użyciu i AddServiceOptions określić typ usługi.

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

Przechwytniki są uruchamiane w kolejności, w której są dodawane do elementu InterceptorCollection. Jeśli zarówno globalne, jak i pojedyncze przechwytniki usługi są skonfigurowane, to globalnie skonfigurowane przechwytniki są uruchamiane przed tymi skonfigurowanymi dla pojedynczej usługi.

Domyślnie przechwytywanie serwerów gRPC ma okres istnienia poszczególnych żądań. Zastąpienie tego zachowania jest możliwe poprzez zarejestrowanie typu przechwytywania za pomocą iniekcji zależności. Poniższy przykład rejestruje element ServerLoggerInterceptor z pojedynczym okresem istnienia:

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

    services.AddSingleton<ServerLoggerInterceptor>();
}

Przechwytywanie gRPC a oprogramowanie pośredniczące

oprogramowanie pośredniczące ASP.NET Core oferuje podobne funkcje w porównaniu do przechwytywania w aplikacjach gRPC opartych na rdzeniach C. ASP.NET Core oprogramowania pośredniczącego i przechwytywania są koncepcyjnie podobne. Oba:

  • Są używane do konstruowania potoku obsługującego żądanie gRPC.
  • Zezwalaj na wykonywanie pracy przed lub po następnym składniku w potoku.
  • Zapewnianie dostępu do usługi HttpContext:
    • W przypadku oprogramowania pośredniczącego parametr HttpContext jest parametrem .
    • W przechwytywaniu HttpContext można uzyskać dostęp przy użyciu parametru ServerCallContext ServerCallContext.GetHttpContext z metodą rozszerzenia. Ta funkcja jest specyficzna dla przechwytywania uruchomionych w ASP.NET Core.

gRPC Interceptor różnice w ASP.NET Core Middleware:

  • Avicode:
    • Działanie na warstwie gRPC abstrakcji przy użyciu klasy ServerCallContext.
    • Zapewnianie dostępu do:
      • Zdeserializowany komunikat wysłany do wywołania.
      • Komunikat zwrócony z wywołania przed jego serializacji.
    • Może przechwytywać wyjątki zgłaszane przez usługi gRPC i obsługiwać je.
  • Oprogramowanie pośredniczące:
    • Uruchamia wszystkie żądania HTTP.
    • Działa przed przechwytywaniem gRPC.
    • Działa na podstawowych komunikatach HTTP/2.
    • Może uzyskiwać dostęp tylko do bajtów ze strumieni żądania i odpowiedzi.

Dodatkowe zasoby