Condividi tramite


Integrazione della factory client gRPC in .NET

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Di James Newton-King

L'integrazione di gRPC con HttpClientFactory offre un modo centralizzato per creare client gRPC. Può essere usato come alternativa alla configurazione delle istanze client gRPC indipendenti. Nel pacchetto NuGet Grpc.Net.ClientFactory è disponibile l'integrazione della fabbrica.

La factory offre i vantaggi seguenti:

  • Fornisce una posizione centrale per la configurazione di istanze client gRPC logiche.
  • Gestisce il ciclo di vita dell'oggetto sottostante HttpClientMessageHandler.
  • Propagazione automatica della scadenza e dell'annullamento in un servizio ASP.NET Core gRPC.

Registrare i client gRPC

Per registrare un client gRPC, il metodo di estensione generico AddGrpcClient può essere usato all'interno di un'istanza di WebApplicationBuilder nel punto di ingresso dell'app in Program.cs, specificando la classe client tipizzata gRPC e l'indirizzo del servizio:

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

Il tipo di client gRPC viene registrato come transitorio con iniezione delle dipendenze. Il client può ora essere inserito e utilizzato direttamente nei tipi creati dall'inserimento delle dipendenze. ASP.NET Core MVC controller, hub e servizi gRPC sono luoghi in cui i client gRPC possono essere iniettati automaticamente.

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

Configurare HttpHandler

HttpClientFactory crea l'oggetto HttpMessageHandler usato dal client gRPC. I metodi standard HttpClientFactory possono essere usati per aggiungere middleware per le richieste in uscita o per configurare l'oggetto sottostante HttpClientHandler di 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;
    });

Per ulteriori informazioni, consultare Effettuare richieste HTTP usando IHttpClientFactory.

Configurare gli intercettori

È possibile aggiungere intercettori gRPC ai client usando il AddInterceptor metodo .

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

Il codice precedente:

  • Registra il tipo GreeterClient.
  • Configura un LoggingInterceptor per questo client. LoggingInterceptor viene creato una sola volta e condiviso tra GreeterClient le istanze.

Per impostazione predefinita, un intercettore viene creato una sola volta e condiviso tra i client. Questo comportamento può essere modificato specificando un ambito al momento della registrazione di un intercettore. La client factory può essere configurata per creare un nuovo intercettore per ogni client specificando InterceptorScope.Client.

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

La creazione di intercettori con ambito client è utile quando un intercettore richiede servizi con ambito specifico o ambito transitorio da DI (Dependency Injection).

È possibile usare un intercettore gRPC o le credenziali del canale per inviare Authorization metadati con ogni richiesta. Per ulteriori informazioni sulla configurazione dell'autenticazione, vedere Inviare un token portatore con la gRPC client factory.

Configurare il canale

È possibile applicare una configurazione aggiuntiva a un canale usando il ConfigureChannel metodo :

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

ConfigureChannel viene passata un'istanza di GrpcChannelOptions. Per ulteriori informazioni, vedere Configurare le opzioni client.

Nota

Alcune proprietà vengono impostate su GrpcChannelOptions prima che il callback ConfigureChannel venga eseguito:

Questi valori possono essere sovrascritti da ConfigureChannel.

Credenziali di chiamata

È possibile aggiungere un'intestazione di autenticazione alle chiamate gRPC usando il AddCallCredentials metodo :

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

Per ulteriori informazioni sulla configurazione delle credenziali di chiamata, vedere Token portatore con la factory client gRPC.

Propagazione di scadenza e di annullamento

I client gRPC creati dalla factory in un servizio gRPC possono essere configurati con EnableCallContextPropagation() per propagare automaticamente la deadline e il token di cancellazione alle chiamate figlie. Il EnableCallContextPropagation() metodo di estensione è disponibile nel pacchetto NuGet Grpc.AspNetCore.Server.ClientFactory .

La propagazione del contesto di chiamata funziona leggendo la scadenza e il token di annullamento dal contesto di richiesta gRPC corrente e propagandoli automaticamente alle chiamate in uscita effettuate dal client gRPC. La propagazione del contesto di chiamata è un ottimo modo per assicurarsi che gli scenari gRPC complessi e annidati trasmettano sempre il termine e l'annullamento.

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

Per impostazione predefinita, EnableCallContextPropagation genera un errore se il client viene usato all'esterno del contesto di una chiamata gRPC. L'errore è progettato per avvisare l'utente che non esiste un contesto di chiamata da propagare. Se si vuole usare il client all'esterno di un contesto di chiamata, eliminare l'errore quando il client è configurato con SuppressContextNotFoundErrors:

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

Per ulteriori informazioni sulla scadenza e l'annullamento RPC, vedere Reliable gRPC services with deadlines and cancellation.

Clienti nominati

In genere, un tipo di client gRPC viene registrato una sola volta e quindi inserito direttamente nel costruttore di un tipo da DI. Tuttavia, esistono scenari in cui è utile avere più configurazioni per un client. Ad esempio, un client che effettua chiamate gRPC con e senza autenticazione.

È possibile registrare più client con lo stesso tipo assegnando a ogni client un nome. Ogni client denominato può avere una propria configurazione. Il metodo di estensione generico AddGrpcClient ha un overload con un parametro name:

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

Il codice precedente:

  • Registra il GreeterClient tipo due volte, specificando un nome univoco per ognuno di essi.
  • Configura impostazioni diverse per ogni client denominato. La GreeterAuthenticated registrazione aggiunge le credenziali al canale in modo che le chiamate gRPC effettuate con esso vengano autenticate.

Un client gRPC denominato viene creato nel codice dell'app usando GrpcClientFactory. Il tipo e il nome del client desiderato sono specificati usando il metodo generico GrpcClientFactory.CreateClient :

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

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

Risorse aggiuntive

L'integrazione di gRPC con HttpClientFactory offre un modo centralizzato per creare client gRPC. Può essere usato come alternativa alla configurazione delle istanze client gRPC indipendenti. Nel pacchetto NuGet Grpc.Net.ClientFactory è disponibile l'integrazione della fabbrica.

La factory offre i vantaggi seguenti:

  • Fornisce una posizione centrale per la configurazione di istanze client gRPC logiche
  • Gestisce il ciclo di vita dell'oggetto sottostante HttpClientMessageHandler
  • Propagazione automatica della scadenza e dell'annullamento in un servizio ASP.NET Core gRPC

Registrare i client gRPC

Per registrare un client gRPC, è possibile usare il metodo di estensione generico AddGrpcClient all'interno Startup.ConfigureServicesdi , specificando la classe client tipizzata gRPC e l'indirizzo del servizio:

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

Il tipo di client gRPC viene registrato come transitorio con iniezione delle dipendenze. Il client può ora essere inserito e utilizzato direttamente nei tipi creati dall'inserimento delle dipendenze. ASP.NET Core MVC controller, hub e servizi gRPC sono luoghi in cui i client gRPC possono essere iniettati automaticamente.

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

Configurare HttpHandler

HttpClientFactory crea l'oggetto HttpMessageHandler usato dal client gRPC. I metodi standard HttpClientFactory possono essere usati per aggiungere middleware per le richieste in uscita o per configurare l'oggetto sottostante HttpClientHandler di HttpClient.

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

Per ulteriori informazioni, consultare Effettuare richieste HTTP usando IHttpClientFactory.

Configurare gli intercettori

È possibile aggiungere intercettori gRPC ai client usando il AddInterceptor metodo .

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

Il codice precedente:

  • Registra il tipo GreeterClient.
  • Configura un LoggingInterceptor per questo client. LoggingInterceptor viene creato una sola volta e condiviso tra GreeterClient le istanze.

Per impostazione predefinita, un intercettore viene creato una sola volta e condiviso tra i client. Questo comportamento può essere modificato specificando un ambito al momento della registrazione di un intercettore. La client factory può essere configurata per creare un nuovo intercettore per ogni client specificando InterceptorScope.Client.

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

La creazione di intercettori con ambito client è utile quando un intercettore richiede servizi con ambito specifico o ambito transitorio da DI (Dependency Injection).

È possibile usare un intercettore gRPC o le credenziali del canale per inviare Authorization metadati con ogni richiesta. Per ulteriori informazioni sulla configurazione dell'autenticazione, vedere Inviare un token portatore con la gRPC client factory.

Configurare il canale

È possibile applicare una configurazione aggiuntiva a un canale usando il ConfigureChannel metodo :

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

ConfigureChannel viene passata un'istanza di GrpcChannelOptions. Per ulteriori informazioni, vedere Configurare le opzioni client.

Nota

Alcune proprietà vengono impostate su GrpcChannelOptions prima che il callback ConfigureChannel venga eseguito:

Questi valori possono essere sovrascritti da ConfigureChannel.

Propagazione di scadenza e di annullamento

I client gRPC creati dalla factory in un servizio gRPC possono essere configurati con EnableCallContextPropagation() per propagare automaticamente la deadline e il token di cancellazione alle chiamate figlie. Il EnableCallContextPropagation() metodo di estensione è disponibile nel pacchetto NuGet Grpc.AspNetCore.Server.ClientFactory .

La propagazione del contesto di chiamata funziona leggendo la scadenza e il token di annullamento dal contesto di richiesta gRPC corrente e propagandoli automaticamente alle chiamate in uscita effettuate dal client gRPC. La propagazione del contesto di chiamata è un ottimo modo per assicurarsi che gli scenari gRPC complessi e annidati trasmettano sempre il termine e l'annullamento.

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

Per impostazione predefinita, EnableCallContextPropagation genera un errore se il client viene usato all'esterno del contesto di una chiamata gRPC. L'errore è progettato per avvisare l'utente che non esiste un contesto di chiamata da propagare. Se si vuole usare il client all'esterno di un contesto di chiamata, eliminare l'errore quando il client è configurato con SuppressContextNotFoundErrors:

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

Per ulteriori informazioni sulla scadenza e l'annullamento RPC, vedere Reliable gRPC services with deadlines and cancellation.

Clienti nominati

In genere, un tipo di client gRPC viene registrato una sola volta e quindi inserito direttamente nel costruttore di un tipo da DI. Tuttavia, esistono scenari in cui è utile avere più configurazioni per un client. Ad esempio, un client che effettua chiamate gRPC con e senza autenticazione.

È possibile registrare più client con lo stesso tipo assegnando a ogni client un nome. Ogni client denominato può avere una propria configurazione. Il metodo di estensione generico AddGrpcClient ha un overload con un parametro name:

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

Il codice precedente:

  • Registra il GreeterClient tipo due volte, specificando un nome univoco per ognuno di essi.
  • Configura impostazioni diverse per ogni client denominato. La GreeterAuthenticated registrazione aggiunge le credenziali al canale in modo che le chiamate gRPC effettuate con esso vengano autenticate.

Un client gRPC denominato viene creato nel codice dell'app usando GrpcClientFactory. Il tipo e il nome del client desiderato sono specificati usando il metodo generico GrpcClientFactory.CreateClient :

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

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

Risorse aggiuntive