Integracja fabryki klienta gRPC na platformie .NET

Autor: James Newton-King

Integracja gRPC z usługą HttpClientFactory oferuje scentralizowany sposób tworzenia klientów gRPC. Może służyć jako alternatywa do konfigurowania autonomicznych wystąpień klienta gRPC. Integracja z fabryką jest dostępna w pakiecie NuGet Grpc.Net.ClientFactory .

Fabryka oferuje następujące korzyści:

  • Zapewnia centralną lokalizację konfigurowania logicznych wystąpień klienta gRPC.
  • Zarządza okresem istnienia bazowego HttpClientMessageHandlerobiektu .
  • Automatyczna propagacja terminu ostatecznego i anulowania w usłudze gRPC platformy ASP.NET Core.

Rejestrowanie klientów gRPC

Aby zarejestrować klienta gRPC, można użyć ogólnej AddGrpcClient metody rozszerzenia w wystąpieniu WebApplicationBuilder punktu wejścia aplikacji w Program.csprogramie , określając typową klasę klienta i adres usługi gRPC:

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

Typ klienta gRPC jest zarejestrowany jako przejściowy z wstrzykiwania zależności (DI). Klient może być teraz wstrzykiwany i używany bezpośrednio w typach utworzonych przez di. ASP.NET podstawowych kontrolerów MVC, centrów i usług gRPC są miejscami, SignalR w których klienci gRPC mogą być automatycznie wstrzykiwani:

public class AggregatorService : Aggregator.AggregatorBase
{
    private readonly Greeter.GreeterClient _client;

    public AggregatorService(Greeter.GreeterClient client)
    {
        _client = client;
    }

    public override async Task SayHellos(HelloRequest request,
        IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
    {
        // Forward the call on to the greeter service
        using (var call = _client.SayHellos(request))
        {
            await foreach (var response in call.ResponseStream.ReadAllAsync())
            {
                await responseStream.WriteAsync(response);
            }
        }
    }
}

Konfigurowanie programu HttpHandler

HttpClientFactory tworzy element HttpMessageHandler używany przez klienta gRPC. Metody standardowe HttpClientFactory mogą służyć do dodawania oprogramowania pośredniczącego żądań wychodzących lub konfigurowania bazowego HttpClientHandler elementu HttpClient:

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

Aby uzyskać więcej informacji, zobacz Make HTTP requests using IHttpClientFactory (Żądania HTTP przy użyciu elementu IHttpClientFactory).

Konfigurowanie przechwytywania

Przechwytywanie gRPC można dodać do klientów przy użyciu AddInterceptor metody .

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddInterceptor<LoggingInterceptor>();

Powyższy kod:

  • Rejestruje GreeterClient typ.
  • Konfiguruje LoggingInterceptor dla tego klienta. LoggingInterceptor jest tworzony raz i współużytkowany między wystąpieniami GreeterClient .

Domyślnie przechwytujący jest tworzony raz i udostępniany między klientami. To zachowanie można zastąpić, określając zakres podczas rejestrowania przechwytywania. Fabrykę klienta można skonfigurować tak, aby utworzyć nowy moduł przechwytujący dla każdego klienta, określając wartość InterceptorScope.Client.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddInterceptor<LoggingInterceptor>(InterceptorScope.Client);

Tworzenie przechwytujących o zakresie klienta jest przydatne, gdy przechwytywanie wymaga usług o określonym zakresie lub przejściowych z di.

Przechwytywanie gRPC lub poświadczeń kanału może służyć do wysyłania Authorization metadanych z każdym żądaniem. Aby uzyskać więcej informacji na temat konfigurowania uwierzytelniania, zobacz Wysyłanie tokenu elementu nośnego za pomocą fabryki klienta gRPC.

Konfigurowanie kanału

Dodatkową konfigurację można zastosować do kanału ConfigureChannel przy użyciu metody :

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(o =>
    {
        o.Credentials = new CustomCredentials();
    });

ConfigureChannel jest przekazywane GrpcChannelOptions wystąpienie. Aby uzyskać więcej informacji, zobacz konfigurowanie opcji klienta.

Uwaga

Niektóre właściwości są ustawiane GrpcChannelOptions przed uruchomieniem wywołania zwrotnego ConfigureChannel :

Te wartości można zastąpić za pomocą metody ConfigureChannel.

Poświadczenia wywołań

Nagłówek uwierzytelniania można dodać do wywołań gRPC przy użyciu AddCallCredentials metody :

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddCallCredentials((context, metadata) =>
    {
        if (!string.IsNullOrEmpty(_token))
        {
            metadata.Add("Authorization", $"Bearer {_token}");
        }
        return Task.CompletedTask;
    });

Aby uzyskać więcej informacji na temat konfigurowania poświadczeń wywołania, zobacz Token elementu nośnego z fabryką klienta gRPC.

Propagacja terminu ostatecznego i anulowania

Klienci gRPC utworzone przez fabrykę w usłudze gRPC można skonfigurować za pomocą polecenia , EnableCallContextPropagation() aby automatycznie propagować ostateczny termin i token anulowania do wywołań podrzędnych. EnableCallContextPropagation() Metoda rozszerzenia jest dostępna w pakiecie NuGet Grpc.AspNetCore.Server.ClientFactory.

Propagacja kontekstu wywołań działa przez odczytanie terminu ostatecznego i tokenu anulowania z bieżącego kontekstu żądania gRPC i automatyczne propagowanie ich do wywołań wychodzących wykonanych przez klienta gRPC. Propagacja kontekstu wywołań to doskonały sposób zapewnienia, że złożone, zagnieżdżone scenariusze gRPC zawsze propagują termin i anulowanie.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation();

Domyślnie zgłasza błąd, EnableCallContextPropagation jeśli klient jest używany poza kontekstem wywołania gRPC. Błąd jest przeznaczony do powiadamiania o tym, że nie ma kontekstu wywołania do propagacji. Jeśli chcesz użyć klienta poza kontekstem wywołania, pomiń błąd, gdy klient jest skonfigurowany za pomocą SuppressContextNotFoundErrorspolecenia :

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);

Aby uzyskać więcej informacji na temat terminów ostatecznych i anulowania RPC, zobacz Reliable gRPC services with deadline and cancellation (Niezawodne usługi gRPC z terminami i anulowaniem).

Nazwani klienci

Zazwyczaj typ klienta gRPC jest rejestrowany raz, a następnie wstrzykiwany bezpośrednio do konstruktora typu przez DI. Istnieją jednak scenariusze, w których warto mieć wiele konfiguracji dla jednego klienta. Na przykład klient, który wykonuje wywołania gRPC z uwierzytelnianiem i bez uwierzytelniania.

Wielu klientów o tym samym typie można zarejestrować, nadając każdemu klientowi nazwę. Każdy nazwany klient może mieć własną konfigurację. Metoda rozszerzenia ogólnego AddGrpcClient ma przeciążenie, które zawiera parametr nazwy:

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>("Greeter", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    });

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>("GreeterAuthenticated", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(o =>
    {
        o.Credentials = new CustomCredentials();
    });

Powyższy kod:

  • Rejestruje GreeterClient typ dwa razy, określając unikatową nazwę dla każdego z nich.
  • Konfiguruje różne ustawienia dla każdego nazwanego klienta. Rejestracja GreeterAuthenticated dodaje poświadczenia do kanału, aby wywołania gRPC wykonane z nim zostały uwierzytelnione.

Nazwany klient gRPC jest tworzony w kodzie aplikacji przy użyciu polecenia GrpcClientFactory. Typ i nazwa żądanego klienta jest określona przy użyciu metody ogólnej GrpcClientFactory.CreateClient :

public class AggregatorService : Aggregator.AggregatorBase
{
    private readonly Greeter.GreeterClient _client;

    public AggregatorService(GrpcClientFactory grpcClientFactory)
    {
        _client = grpcClientFactory.CreateClient<Greeter.GreeterClient>("GreeterAuthenticated");
    }
}

Dodatkowe zasoby

Integracja gRPC z usługą HttpClientFactory oferuje scentralizowany sposób tworzenia klientów gRPC. Może służyć jako alternatywa do konfigurowania autonomicznych wystąpień klienta gRPC. Integracja z fabryką jest dostępna w pakiecie NuGet Grpc.Net.ClientFactory .

Fabryka oferuje następujące korzyści:

  • Zapewnia centralną lokalizację do konfigurowania logicznych wystąpień klienta gRPC
  • Zarządza okresem istnienia bazowego HttpClientMessageHandler
  • Automatyczna propagacja terminu ostatecznego i anulowania w usłudze gRPC platformy ASP.NET Core

Rejestrowanie klientów gRPC

Aby zarejestrować klienta gRPC, AddGrpcClient można użyć ogólnej metody rozszerzenia w programie Startup.ConfigureServices, określając typową klasę klienta i adres usługi gRPC:

services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
    o.Address = new Uri("https://localhost:5001");
});

Typ klienta gRPC jest zarejestrowany jako przejściowy z wstrzykiwania zależności (DI). Klient może być teraz wstrzykiwany i używany bezpośrednio w typach utworzonych przez di. ASP.NET podstawowych kontrolerów MVC, centrów i usług gRPC są miejscami, SignalR w których klienci gRPC mogą być automatycznie wstrzykiwani:

public class AggregatorService : Aggregator.AggregatorBase
{
    private readonly Greeter.GreeterClient _client;

    public AggregatorService(Greeter.GreeterClient client)
    {
        _client = client;
    }

    public override async Task SayHellos(HelloRequest request,
        IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
    {
        // Forward the call on to the greeter service
        using (var call = _client.SayHellos(request))
        {
            await foreach (var response in call.ResponseStream.ReadAllAsync())
            {
                await responseStream.WriteAsync(response);
            }
        }
    }
}

Konfigurowanie programu HttpHandler

HttpClientFactory tworzy element HttpMessageHandler używany przez klienta gRPC. Metody standardowe HttpClientFactory mogą służyć do dodawania oprogramowania pośredniczącego żądań wychodzących lub konfigurowania bazowego HttpClientHandler elementu HttpClient:

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

Aby uzyskać więcej informacji, zobacz Make HTTP requests using IHttpClientFactory (Żądania HTTP przy użyciu elementu IHttpClientFactory).

Konfigurowanie przechwytywania

Przechwytywanie gRPC można dodać do klientów przy użyciu AddInterceptor metody .

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddInterceptor<LoggingInterceptor>();

Powyższy kod:

  • Rejestruje GreeterClient typ.
  • Konfiguruje LoggingInterceptor dla tego klienta. LoggingInterceptor jest tworzony raz i współużytkowany między wystąpieniami GreeterClient .

Domyślnie przechwytujący jest tworzony raz i udostępniany między klientami. To zachowanie można zastąpić, określając zakres podczas rejestrowania przechwytywania. Fabrykę klienta można skonfigurować tak, aby utworzyć nowy moduł przechwytujący dla każdego klienta, określając wartość InterceptorScope.Client.

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddInterceptor<LoggingInterceptor>(InterceptorScope.Client);

Tworzenie przechwytujących o zakresie klienta jest przydatne, gdy przechwytywanie wymaga usług o określonym zakresie lub przejściowych z di.

Przechwytywanie gRPC lub poświadczeń kanału może służyć do wysyłania Authorization metadanych z każdym żądaniem. Aby uzyskać więcej informacji na temat konfigurowania uwierzytelniania, zobacz Wysyłanie tokenu elementu nośnego za pomocą fabryki klienta gRPC.

Konfigurowanie kanału

Dodatkową konfigurację można zastosować do kanału ConfigureChannel przy użyciu metody :

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(o =>
    {
        o.Credentials = new CustomCredentials();
    });

ConfigureChannel jest przekazywane GrpcChannelOptions wystąpienie. Aby uzyskać więcej informacji, zobacz konfigurowanie opcji klienta.

Uwaga

Niektóre właściwości są ustawiane GrpcChannelOptions przed uruchomieniem wywołania zwrotnego ConfigureChannel :

Te wartości można zastąpić za pomocą metody ConfigureChannel.

Propagacja terminu ostatecznego i anulowania

Klienci gRPC utworzone przez fabrykę w usłudze gRPC można skonfigurować za pomocą polecenia , EnableCallContextPropagation() aby automatycznie propagować ostateczny termin i token anulowania do wywołań podrzędnych. EnableCallContextPropagation() Metoda rozszerzenia jest dostępna w pakiecie NuGet Grpc.AspNetCore.Server.ClientFactory.

Propagacja kontekstu wywołań działa przez odczytanie terminu ostatecznego i tokenu anulowania z bieżącego kontekstu żądania gRPC i automatyczne propagowanie ich do wywołań wychodzących wykonanych przez klienta gRPC. Propagacja kontekstu wywołań to doskonały sposób zapewnienia, że złożone, zagnieżdżone scenariusze gRPC zawsze propagują termin i anulowanie.

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation();

Domyślnie zgłasza błąd, EnableCallContextPropagation jeśli klient jest używany poza kontekstem wywołania gRPC. Błąd jest przeznaczony do powiadamiania o tym, że nie ma kontekstu wywołania do propagacji. Jeśli chcesz użyć klienta poza kontekstem wywołania, pomiń błąd, gdy klient jest skonfigurowany za pomocą SuppressContextNotFoundErrorspolecenia :

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);

Aby uzyskać więcej informacji na temat terminów ostatecznych i anulowania RPC, zobacz Reliable gRPC services with deadline and cancellation (Niezawodne usługi gRPC z terminami i anulowaniem).

Nazwani klienci

Zazwyczaj typ klienta gRPC jest rejestrowany raz, a następnie wstrzykiwany bezpośrednio do konstruktora typu przez DI. Istnieją jednak scenariusze, w których warto mieć wiele konfiguracji dla jednego klienta. Na przykład klient, który wykonuje wywołania gRPC z uwierzytelnianiem i bez uwierzytelniania.

Wielu klientów o tym samym typie można zarejestrować, nadając każdemu klientowi nazwę. Każdy nazwany klient może mieć własną konfigurację. Metoda rozszerzenia ogólnego AddGrpcClient ma przeciążenie, które zawiera parametr nazwy:

services
    .AddGrpcClient<Greeter.GreeterClient>("Greeter", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    });

services
    .AddGrpcClient<Greeter.GreeterClient>("GreeterAuthenticated", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(o =>
    {
        o.Credentials = new CustomCredentials();
    });

Powyższy kod:

  • Rejestruje GreeterClient typ dwa razy, określając unikatową nazwę dla każdego z nich.
  • Konfiguruje różne ustawienia dla każdego nazwanego klienta. Rejestracja GreeterAuthenticated dodaje poświadczenia do kanału, aby wywołania gRPC wykonane z nim zostały uwierzytelnione.

Nazwany klient gRPC jest tworzony w kodzie aplikacji przy użyciu polecenia GrpcClientFactory. Typ i nazwa żądanego klienta jest określona przy użyciu metody ogólnej GrpcClientFactory.CreateClient :

public class AggregatorService : Aggregator.AggregatorBase
{
    private readonly Greeter.GreeterClient _client;

    public AggregatorService(GrpcClientFactory grpcClientFactory)
    {
        _client = grpcClientFactory.CreateClient<Greeter.GreeterClient>("GreeterAuthenticated");
    }
}

Dodatkowe zasoby