Integração de fábrica do cliente gRPC no .NET
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para a versão atual, consulte a versão .NET 9 deste artigo.
A integração do gRPC com o HttpClientFactory
oferece uma maneira centralizada de criar clientes gRPC. Ele pode ser usado como uma alternativa para configurar instâncias de cliente gRPC autônomas. A integração de fábrica está disponível no pacote NuGet Grpc.Net.ClientFactory.
O alocador oferece os seguintes benefícios:
- Fornece um local central para configurar instâncias de cliente gRPC lógicas.
- Gerencia o tempo de vida do
HttpClientMessageHandler
subjacente. - Propagação automática de prazo e cancelamento em um serviço gRPC do ASP.NET Core.
Registrar clientes gRPC
Para registrar um cliente gRPC, o método de extensão genérica AddGrpcClient
pode ser usado em uma instância do WebApplicationBuilder no ponto de entrada do aplicativo em Program.cs
, especificando a classe de cliente e o endereço de serviço tipado do gRPC:
builder.Services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
});
O tipo de cliente gRPC é registrado como transitório com DI (injeção de dependência). O cliente agora pode ser injetado e consumido diretamente em tipos criados pela DI. Os controladores MVC do ASP.NET Core, os hubs do SignalR e os serviços gRPC são locais em que os clientes gRPC podem ser injetados 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);
}
}
}
}
Configurar o HttpHandler
O HttpClientFactory
cria o HttpMessageHandler
usado pelo cliente gRPC. Os métodos padrão do HttpClientFactory
podem ser usados para adicionar o middleware de solicitação de saída ou para configurar o HttpClientHandler
subjacente do 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;
});
Para obter mais informações, confira Fazer solicitações HTTP usando IHttpClientFactory.
Configurar interceptadores
Os interceptadores gRPC podem ser adicionados aos clientes usando o método AddInterceptor
.
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddInterceptor<LoggingInterceptor>();
O código anterior:
- Registra o tipo do
GreeterClient
. - Configura um
LoggingInterceptor
para esse cliente. OLoggingInterceptor
é criado uma vez e compartilhado entre as instâncias doGreeterClient
.
Por padrão, um interceptador é criado uma vez e compartilhado entre clientes. Esse comportamento pode ser substituído especificando um escopo ao registrar um interceptador. A fábrica de clientes pode ser configurada para criar um novo interceptador para cada cliente especificando o InterceptorScope.Client
.
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddInterceptor<LoggingInterceptor>(InterceptorScope.Client);
A criação de interceptadores no escopo do cliente é útil quando um interceptador requer serviços com escopo ou escopos transitórios da DI.
Um interceptador gRPC ou credenciais de canal podem ser usados para enviar metadados de Authorization
com cada solicitação. Para obter mais informações sobre como configurar a autenticação, confira Enviar um token de portador com o alocador de clientes gRPC.
Configurar canal
É possível aplicar configuração adicional a um canal usando o método ConfigureChannel
:
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.ConfigureChannel(o =>
{
o.Credentials = new CustomCredentials();
});
O ConfigureChannel
é passado por uma instância GrpcChannelOptions
. Para obter mais informações, confira Configurar opções de cliente.
Observação
Algumas propriedades são definidas em GrpcChannelOptions
antes que o retorno de chamada ConfigureChannel
seja executado:
- O
HttpHandler
é definido como o resultado de ConfigurePrimaryHttpMessageHandler. - O
LoggerFactory
é definido como o ILoggerFactory resolvido por meio da DI.
Esses valores podem ser substituídos por ConfigureChannel
.
Credenciais de chamada
Um cabeçalho de autenticação pode ser adicionado a chamadas gRPC usando o método AddCallCredentials
:
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;
});
Para obter mais informações sobre como configurar credenciais de chamada, confira Token de portador com o alocador de clientes gRPC.
Propagação de prazo final e cancelamento
Os clientes gRPC criados pelo alocador em um serviço gRPC podem ser configurados com EnableCallContextPropagation()
para propagar automaticamente o token de prazo final e cancelamento para chamadas filho. O método de extensão EnableCallContextPropagation()
está disponível no pacote NuGet Grpc.AspNetCore.Server.ClientFactory.
A propagação de contexto de chamada funciona com a leitura do prazo final e o token de cancelamento do contexto de solicitação gRPC atual, propagando-os automaticamente para chamadas de saída feitas pelo cliente gRPC. A propagação de contexto de chamada é uma excelente maneira de garantir que cenários gRPC complexos e aninhados sempre propaguem o prazo final e o cancelamento.
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.EnableCallContextPropagation();
Por padrão, EnableCallContextPropagation
gerará um erro se o cliente for usado fora do contexto de uma chamada gRPC. O erro foi projetado para alertar você de que não há um contexto de chamada a ser propagado. Se você quiser usar o cliente fora de um contexto de chamada, suprima o erro quando o cliente estiver configurado com SuppressContextNotFoundErrors
:
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);
Para obter mais informações sobre prazos finais e cancelamento de RPC, confira Serviços gRPC confiáveis com prazos finais e cancelamento.
Clientes nomeados
Normalmente, um tipo de cliente gRPC é registrado uma vez e, em seguida, injetado diretamente no construtor de um tipo por DI. No entanto, há cenários em que é útil ter várias configurações para um cliente. Por exemplo, um cliente que faz chamadas gRPC com e sem autenticação.
Vários clientes com o mesmo tipo podem ser registrados dando um nome a cada cliente. Cada cliente nomeado pode ter sua própria configuração. O método de extensão genérico AddGrpcClient
tem uma sobrecarga que inclui um parâmetro de nome:
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();
});
O código anterior:
- Registra o
GreeterClient
tipo duas vezes, especificando um nome exclusivo para cada um. - Define configurações diferentes para cada cliente nomeado. O registro
GreeterAuthenticated
adiciona credenciais ao canal para que as chamadas gRPC feitas com ele sejam autenticadas.
Um cliente gRPC nomeado é criado no código do aplicativo usando GrpcClientFactory
. O tipo e o nome do cliente desejado são especificados usando o método genérico GrpcClientFactory.CreateClient
:
public class AggregatorService : Aggregator.AggregatorBase
{
private readonly Greeter.GreeterClient _client;
public AggregatorService(GrpcClientFactory grpcClientFactory)
{
_client = grpcClientFactory.CreateClient<Greeter.GreeterClient>("GreeterAuthenticated");
}
}
Recursos adicionais
A integração do gRPC com o HttpClientFactory
oferece uma maneira centralizada de criar clientes gRPC. Ele pode ser usado como uma alternativa para configurar instâncias de cliente gRPC autônomas. A integração de fábrica está disponível no pacote NuGet Grpc.Net.ClientFactory.
O alocador oferece os seguintes benefícios:
- Fornece um local central para configurar instâncias de cliente gRPC lógicas
- Gerencia o tempo de vida do
HttpClientMessageHandler
subjacente - Propagação automática de prazo e cancelamento em um serviço gRPC do ASP.NET Core
Registrar clientes gRPC
Para registrar um cliente gRPC, o método de extensão AddGrpcClient
genérico pode ser usado no Startup.ConfigureServices
, especificando a classe de cliente e o endereço de serviço tipados do gRPC:
services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
});
O tipo de cliente gRPC é registrado como transitório com DI (injeção de dependência). O cliente agora pode ser injetado e consumido diretamente em tipos criados pela DI. Os controladores MVC do ASP.NET Core, os hubs do SignalR e os serviços gRPC são locais em que os clientes gRPC podem ser injetados 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);
}
}
}
}
Configurar o HttpHandler
O HttpClientFactory
cria o HttpMessageHandler
usado pelo cliente gRPC. Os métodos padrão do HttpClientFactory
podem ser usados para adicionar o middleware de solicitação de saída ou para configurar o HttpClientHandler
subjacente do HttpClient
:
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(LoadCertificate());
return handler;
});
Para obter mais informações, confira Fazer solicitações HTTP usando IHttpClientFactory.
Configurar interceptadores
Os interceptadores gRPC podem ser adicionados aos clientes usando o método AddInterceptor
.
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddInterceptor<LoggingInterceptor>();
O código anterior:
- Registra o tipo do
GreeterClient
. - Configura um
LoggingInterceptor
para esse cliente. OLoggingInterceptor
é criado uma vez e compartilhado entre as instâncias doGreeterClient
.
Por padrão, um interceptador é criado uma vez e compartilhado entre clientes. Esse comportamento pode ser substituído especificando um escopo ao registrar um interceptador. A fábrica de clientes pode ser configurada para criar um novo interceptador para cada cliente especificando o InterceptorScope.Client
.
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddInterceptor<LoggingInterceptor>(InterceptorScope.Client);
A criação de interceptadores no escopo do cliente é útil quando um interceptador requer serviços com escopo ou escopos transitórios da DI.
Um interceptador gRPC ou credenciais de canal podem ser usados para enviar metadados de Authorization
com cada solicitação. Para obter mais informações sobre como configurar a autenticação, confira Enviar um token de portador com o alocador de clientes gRPC.
Configurar canal
É possível aplicar configuração adicional a um canal usando o método ConfigureChannel
:
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.ConfigureChannel(o =>
{
o.Credentials = new CustomCredentials();
});
O ConfigureChannel
é passado por uma instância GrpcChannelOptions
. Para obter mais informações, confira Configurar opções de cliente.
Observação
Algumas propriedades são definidas em GrpcChannelOptions
antes que o retorno de chamada ConfigureChannel
seja executado:
- O
HttpHandler
é definido como o resultado de ConfigurePrimaryHttpMessageHandler. - O
LoggerFactory
é definido como o ILoggerFactory resolvido por meio da DI.
Esses valores podem ser substituídos por ConfigureChannel
.
Propagação de prazo final e cancelamento
Os clientes gRPC criados pelo alocador em um serviço gRPC podem ser configurados com EnableCallContextPropagation()
para propagar automaticamente o token de prazo final e cancelamento para chamadas filho. O método de extensão EnableCallContextPropagation()
está disponível no pacote NuGet Grpc.AspNetCore.Server.ClientFactory.
A propagação de contexto de chamada funciona com a leitura do prazo final e o token de cancelamento do contexto de solicitação gRPC atual, propagando-os automaticamente para chamadas de saída feitas pelo cliente gRPC. A propagação de contexto de chamada é uma excelente maneira de garantir que cenários gRPC complexos e aninhados sempre propaguem o prazo final e o cancelamento.
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.EnableCallContextPropagation();
Por padrão, EnableCallContextPropagation
gerará um erro se o cliente for usado fora do contexto de uma chamada gRPC. O erro foi projetado para alertar você de que não há um contexto de chamada a ser propagado. Se você quiser usar o cliente fora de um contexto de chamada, suprima o erro quando o cliente estiver configurado com SuppressContextNotFoundErrors
:
services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);
Para obter mais informações sobre prazos finais e cancelamento de RPC, confira Serviços gRPC confiáveis com prazos finais e cancelamento.
Clientes nomeados
Normalmente, um tipo de cliente gRPC é registrado uma vez e, em seguida, injetado diretamente no construtor de um tipo por DI. No entanto, há cenários em que é útil ter várias configurações para um cliente. Por exemplo, um cliente que faz chamadas gRPC com e sem autenticação.
Vários clientes com o mesmo tipo podem ser registrados dando um nome a cada cliente. Cada cliente nomeado pode ter sua própria configuração. O método de extensão genérico AddGrpcClient
tem uma sobrecarga que inclui um parâmetro de nome:
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();
});
O código anterior:
- Registra o
GreeterClient
tipo duas vezes, especificando um nome exclusivo para cada um. - Define configurações diferentes para cada cliente nomeado. O registro
GreeterAuthenticated
adiciona credenciais ao canal para que as chamadas gRPC feitas com ele sejam autenticadas.
Um cliente gRPC nomeado é criado no código do aplicativo usando GrpcClientFactory
. O tipo e o nome do cliente desejado são especificados usando o método genérico GrpcClientFactory.CreateClient
:
public class AggregatorService : Aggregator.AggregatorBase
{
private readonly Greeter.GreeterClient _client;
public AggregatorService(GrpcClientFactory grpcClientFactory)
{
_client = grpcClientFactory.CreateClient<Greeter.GreeterClient>("GreeterAuthenticated");
}
}