gRPC-Web em aplicativos gRPC no ASP.NET Core

Por James Newton-King

Saiba como configurar um serviço gRPC ASP.NET Core existente para ser chamado de aplicativos de navegador, usando o protocolo gRPC-Web. O gRPC-Web permite que o JavaScript do navegador e os aplicativos Blazor chamem serviços gRPC. Não é possível chamar um serviço gRPC HTTP/2 de um aplicativo baseado em navegador. Os serviços gRPC hospedados em ASP.NET Core podem ser configurados para dar suporte a gRPC-Web junto com HTTP/2 gRPC.

Para obter instruções sobre como adicionar um serviço gRPC a um aplicativo ASP.NET Core existente, confira Adicionar serviços gRPC a um aplicativo ASP.NET Core.

Para obter instruções sobre como criar um projeto gRPC, confira Criar um cliente e um servidor gRPC do .NET Core no ASP.NET Core.

ASP.NET Core gRPC-Web versus Envoy

Há duas opções para adicionar gRPC-Web a um aplicativo ASP.NET Core:

  • Suporte a gRPC-Web junto com gRPC HTTP/2 em ASP.NET Core. Essa opção usa o middleware fornecido pelo pacote Grpc.AspNetCore.Web.
  • Use o suporte a gRPC-Web do proxy Envoy para converter gRPC-Web para gRPC HTTP/2. Em seguida, a chamada convertida é encaminhada para o aplicativo ASP.NET Core.

Há prós e contras em cada abordagem. Se o ambiente de um aplicativo já estiver usando o Envoy como proxy, talvez faça sentido também usar o Envoy para fornecer suporte a gRPC-Web. Para uma solução básica para gRPC-Web que requer apenas ASP.NET Core, Grpc.AspNetCore.Web é uma boa opção.

Configurar gRPC-Web no ASP.NET Core

Os serviços gRPC hospedados em ASP.NET Core podem ser configurados para dar suporte a gRPC-Web junto com HTTP/2 gRPC. O gRPC-Web não exige nenhuma alteração nos serviços. A única modificação está na configuração do middleware em Program.cs.

Para habilitar o gRPC-Web com um serviço gRPC ASP.NET Core:

  • Adicione uma referência ao pacote Grpc.AspNetCore.Web.
  • Configure o aplicativo para usar gRPC-Web adicionando UseGrpcWeb e EnableGrpcWeb a Program.cs:
using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

app.UseGrpcWeb();

app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "This gRPC service is gRPC-Web enabled and is callable from browser apps uisng the gRPC-Web protocal");

app.Run();

O código anterior:

  • Adiciona o middleware gRPC-Web, UseGrpcWeb, após o roteamento e antes dos pontos de extremidade.
  • Especifica que o método endpoints.MapGrpcService<GreeterService>() dá suporte a gRPC-Web com EnableGrpcWeb.

Como alternativa, o middleware gRPC-Web pode ser configurado para que todos os serviços ofereçam suporte a gRPC-Web por padrão e para que EnableGrpcWeb não seja necessário. Especifique new GrpcWebOptions { DefaultEnabled = true } quando o middleware for adicionado.

using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });

app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "All gRPC service are supported by default in this example, and are callable from browser apps uisng the gRPC-Web protocal");

app.Run();

Observação

Há um problema conhecido que faz com que o gRPC-Web falhe quando hospedado por HTTP.sys no .NET Core 3.x.

Uma solução alternativa para fazer com que o gRPC-Web funcione no HTTP.sys está disponível em Grpc-web experimental e UseHttpSys()? (grpc/grpc-dotnet #853).

gRPC-Web e CORS

A segurança do navegador impede que uma página da Web faça solicitações para um domínio diferente daquele que ofereceu a página da Web. Essa restrição se aplica à realização de chamadas gRPC-Web com aplicativos de navegador. Por exemplo, um aplicativo de navegador oferecido por https://www.contoso.com fica impedido de chamar serviços gRPC-Web hospedados em https://services.contoso.com. O CORS (Compartilhamento de Recursos entre Origens) pode ser usado para afrouxar essa restrição.

Para permitir que um aplicativo de navegador faça chamadas gRPC-Web entre origens, configure o CORS no ASP.NET Core. Use o suporte interno ao CORS e exponha cabeçalhos específicos do gRPC com WithExposedHeaders.

using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

builder.Services.AddCors(o => o.AddPolicy("AllowAll", builder =>
{
    builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
}));

var app = builder.Build();

app.UseGrpcWeb();
app.UseCors();

app.MapGrpcService<GreeterService>().EnableGrpcWeb()
                                    .RequireCors("AllowAll");

app.MapGet("/", () => "This gRPC service is gRPC-Web enabled, CORS enabled, and is callable from browser apps uisng the gRPC-Web protocal");

app.Run();

O código anterior:

  • Chama AddCors para adicionar serviços CORS e configurar uma política CORS que expõe cabeçalhos específicos ao gRPC.
  • Chama UseCors para adicionar o middleware CORS após a configuração de roteamento e antes da configuração dos pontos de extremidade.
  • Especifica que o método endpoints.MapGrpcService<GreeterService>() dá suporte a gRPC-Web com RequireCors.

gRPC-Web e streaming

O gRPC tradicional por HTTP/2 dá suporte a streaming de cliente, servidor e bidirecional. O gRPC-Web oferece suporte limitado para streaming:

  • Os clientes do navegador gRPC-Web não dão suporte à chamada de métodos de streaming de cliente e bidirecional.
  • Os clientes .NET de gRPC-Web não dão suporte à chamada de métodos de streaming de cliente e bidirecional sobre HTTP/1.1.
  • ASP.NET Core serviços gRPC hospedados no Serviço de Aplicativo do Azure e o IIS não dão suporte ao streaming bidirecional.

Ao usar gRPC-Web, recomendamos apenas o uso de métodos unários e métodos de streaming de servidor.

Protocolo HTTP

O modelo de serviço gRPC do ASP.NET Core, incluído no SDK do .NET, cria um aplicativo configurado apenas para HTTP/2. Isso é um bom padrão quando um aplicativo dá suporte apenas ao gRPC tradicional por HTTP/2. O gRPC-Web, no entanto, funciona com HTTP/1.1 e HTTP/2. Algumas plataformas, como UWP ou Unity, não podem usar HTTP/2. Para dar suporte a todos os aplicativos cliente, configure o servidor para habilitar HTTP/1.1 e HTTP/2.

Atualize o protocolo padrão em appsettings.json:

{
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http1AndHttp2"
    }
  }
}

Como alternativa, configure pontos de extremidade Kestrel no código de inicialização.

A habilitação de HTTP/1.1 e HTTP/2 na mesma porta exige TLS para negociação de protocolo. Para obter mais informações, confira Negociação de protocolo gRPC do ASP.NET Core.

Chamar gRPC-Web do navegador

Os aplicativos de navegador podem usar gRPC-Web para chamar serviços gRPC. Há alguns requisitos e limitações ao chamar serviços gRPC com gRPC-Web do navegador:

  • O servidor deve conter a configuração para dar suporte a gRPC-Web.
  • Não há suporte para chamadas a streaming de cliente e bidirecional. Há suporte para streaming de servidor.
  • Para chamar serviços gRPC em um domínio diferente, você precisa da configuração de CORS no servidor.

Cliente gRPC-Web em JavaScript

Há um cliente gRPC-Web em JavaScript. Para obter instruções sobre como usar gRPC-Web em JavaScript, confira Escrever código de cliente em JavaScript com gRPC-Web.

Configurar gRPC-Web com o cliente gRPC de .NET

O cliente gRPC de .NET pode ser configurado para fazer chamadas a gRPC-Web. Isso é útil para aplicativos Blazor WebAssembly, que são hospedados no navegador e têm as mesmas limitações de HTTP do código JavaScript. Chamar gRPC-Web com um cliente .NET é o mesmo que HTTP/2 gRPC. A única modificação é como o canal é criado.

Para usar gRPC-Web:

  • Adicione uma referência ao pacote Grpc.Net.Client.Web.
  • Verifique se a referência ao pacote Grpc.Net.Client é a versão 2.29.0 ou posterior.
  • Configure o canal para usar o GrpcWebHandler:
var channel = GrpcChannel.ForAddress("https://localhost:53305", new GrpcChannelOptions
{
    HttpHandler = new GrpcWebHandler(new HttpClientHandler())
});

var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(
                  new HelloRequest { Name = "GreeterClient" });

O código anterior:

  • Configura um canal para usar gRPC-Web.
  • Cria um cliente e faz uma chamada usando o canal .

GrpcWebHandler tem as seguintes opções de configuração:

  • InnerHandler: o HttpMessageHandler subjacente que faz a solicitação HTTP gRPC, por exemplo, HttpClientHandler.
  • GrpcWebMode: um tipo de enumeração que especifica se a solicitação HTTP gRPC Content-Type é application/grpc-web ou application/grpc-web-text.
    • GrpcWebMode.GrpcWeb configura o envio de conteúdo sem codificação. Valor padrão.
    • GrpcWebMode.GrpcWebText configura o conteúdo codificado em base64. Necessário para chamadas de streaming de servidor em navegadores.
  • HttpVersion: protocolo HTTP Version usado para definir HttpRequestMessage.Version na solicitação HTTP do gRPC subjacente. O gRPC-Web não requer uma versão específica e não substitui o padrão, a menos que especificado.

Importante

Os clientes gRPC gerados têm métodos síncronos e assíncronos para chamar métodos unários. Por exemplo, SayHello é síncrono e SayHelloAsync é assíncrono. Métodos assíncronos são sempre necessários em Blazor WebAssembly. Chamar um método síncrono em um aplicativo Blazor WebAssembly faz com que o aplicativo fique sem resposta.

Usar a fábrica de clientes gRPC com gRPC-Web

Crie um cliente .NET compatível com gRPC-Web usando a fábrica de clientes gRPC:

  • Adicione referências de pacote ao arquivo de projeto para os seguintes pacotes:
  • Registre um cliente gRPC com DI (injeção de dependência) usando o método de extensão genérico AddGrpcClient. Em um aplicativo Blazor WebAssembly, os serviços são registrados com DI no Program.cs.
  • Configure GrpcWebHandler usando o método de extensão ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Para saber mais, confira Integração de fábrica do cliente gRPC no .NET.

Recursos adicionais

Saiba como configurar um serviço gRPC ASP.NET Core existente para ser chamado de aplicativos de navegador, usando o protocolo gRPC-Web. O gRPC-Web permite que o JavaScript do navegador e os aplicativos Blazor chamem serviços gRPC. Não é possível chamar um serviço gRPC HTTP/2 de um aplicativo baseado em navegador. Os serviços gRPC hospedados em ASP.NET Core podem ser configurados para dar suporte a gRPC-Web junto com HTTP/2 gRPC.

Para obter instruções sobre como adicionar um serviço gRPC a um aplicativo ASP.NET Core existente, confira Adicionar serviços gRPC a um aplicativo ASP.NET Core.

Para obter instruções sobre como criar um projeto gRPC, confira Criar um cliente e um servidor gRPC do .NET Core no ASP.NET Core.

ASP.NET Core gRPC-Web versus Envoy

Há duas opções para adicionar gRPC-Web a um aplicativo ASP.NET Core:

  • Suporte a gRPC-Web junto com gRPC HTTP/2 em ASP.NET Core. Essa opção usa o middleware fornecido pelo pacote Grpc.AspNetCore.Web.
  • Use o suporte a gRPC-Web do proxy Envoy para converter gRPC-Web para gRPC HTTP/2. Em seguida, a chamada convertida é encaminhada para o aplicativo ASP.NET Core.

Há prós e contras em cada abordagem. Se o ambiente de um aplicativo já estiver usando o Envoy como proxy, talvez faça sentido também usar o Envoy para fornecer suporte a gRPC-Web. Para uma solução básica para gRPC-Web que requer apenas ASP.NET Core, Grpc.AspNetCore.Web é uma boa opção.

Configurar gRPC-Web no ASP.NET Core

Os serviços gRPC hospedados em ASP.NET Core podem ser configurados para dar suporte a gRPC-Web junto com HTTP/2 gRPC. O gRPC-Web não exige nenhuma alteração nos serviços. A única modificação está na configuração do middleware em Program.cs.

Para habilitar o gRPC-Web com um serviço gRPC ASP.NET Core:

  • Adicione uma referência ao pacote Grpc.AspNetCore.Web.
  • Configure o aplicativo para usar gRPC-Web adicionando UseGrpcWeb e EnableGrpcWeb a Program.cs:
using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

app.UseGrpcWeb();

app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "This gRPC service is gRPC-Web enabled and is callable from browser apps uisng the gRPC-Web protocal");

app.Run();

O código anterior:

  • Adiciona o middleware gRPC-Web, UseGrpcWeb, após o roteamento e antes dos pontos de extremidade.
  • Especifica que o método endpoints.MapGrpcService<GreeterService>() dá suporte a gRPC-Web com EnableGrpcWeb.

Como alternativa, o middleware gRPC-Web pode ser configurado para que todos os serviços ofereçam suporte a gRPC-Web por padrão e para que EnableGrpcWeb não seja necessário. Especifique new GrpcWebOptions { DefaultEnabled = true } quando o middleware for adicionado.

using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });

app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "All gRPC service are supported by default in this example, and are callable from browser apps uisng the gRPC-Web protocal");

app.Run();

Observação

Há um problema conhecido que faz com que o gRPC-Web falhe quando hospedado por HTTP.sys no .NET Core 3.x.

Uma solução alternativa para fazer com que o gRPC-Web funcione no HTTP.sys está disponível em Grpc-web experimental e UseHttpSys()? (grpc/grpc-dotnet #853).

gRPC-Web e CORS

A segurança do navegador impede que uma página da Web faça solicitações para um domínio diferente daquele que ofereceu a página da Web. Essa restrição se aplica à realização de chamadas gRPC-Web com aplicativos de navegador. Por exemplo, um aplicativo de navegador oferecido por https://www.contoso.com fica impedido de chamar serviços gRPC-Web hospedados em https://services.contoso.com. O CORS (Compartilhamento de Recursos entre Origens) pode ser usado para afrouxar essa restrição.

Para permitir que um aplicativo de navegador faça chamadas gRPC-Web entre origens, configure o CORS no ASP.NET Core. Use o suporte interno ao CORS e exponha cabeçalhos específicos do gRPC com WithExposedHeaders.

using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

builder.Services.AddCors(o => o.AddPolicy("AllowAll", builder =>
{
    builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
}));

var app = builder.Build();

app.UseGrpcWeb();
app.UseCors();

app.MapGrpcService<GreeterService>().EnableGrpcWeb()
                                    .RequireCors("AllowAll");

app.MapGet("/", () => "This gRPC service is gRPC-Web enabled, CORS enabled, and is callable from browser apps uisng the gRPC-Web protocal");

app.Run();

O código anterior:

  • Chama AddCors para adicionar serviços CORS e configurar uma política CORS que expõe cabeçalhos específicos ao gRPC.
  • Chama UseCors para adicionar o middleware CORS após a configuração de roteamento e antes da configuração dos pontos de extremidade.
  • Especifica que o método endpoints.MapGrpcService<GreeterService>() dá suporte a gRPC-Web com RequireCors.

gRPC-Web e streaming

O gRPC tradicional por HTTP/2 dá suporte a streaming de cliente, servidor e bidirecional. O gRPC-Web oferece suporte limitado para streaming:

  • Os clientes do navegador gRPC-Web não dão suporte à chamada de métodos de streaming de cliente e bidirecional.
  • Os clientes .NET de gRPC-Web não dão suporte à chamada de métodos de streaming de cliente e bidirecional sobre HTTP/1.1.
  • ASP.NET Core serviços gRPC hospedados no Serviço de Aplicativo do Azure e o IIS não dão suporte ao streaming bidirecional.

Ao usar gRPC-Web, recomendamos apenas o uso de métodos unários e métodos de streaming de servidor.

Protocolo HTTP

O modelo de serviço gRPC do ASP.NET Core, incluído no SDK do .NET, cria um aplicativo configurado apenas para HTTP/2. Isso é um bom padrão quando um aplicativo dá suporte apenas ao gRPC tradicional por HTTP/2. O gRPC-Web, no entanto, funciona com HTTP/1.1 e HTTP/2. Algumas plataformas, como UWP ou Unity, não podem usar HTTP/2. Para dar suporte a todos os aplicativos cliente, configure o servidor para habilitar HTTP/1.1 e HTTP/2.

Atualize o protocolo padrão em appsettings.json:

{
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http1AndHttp2"
    }
  }
}

Como alternativa, configure pontos de extremidade Kestrel no código de inicialização.

A habilitação de HTTP/1.1 e HTTP/2 na mesma porta exige TLS para negociação de protocolo. Para obter mais informações, confira Negociação de protocolo gRPC do ASP.NET Core.

Chamar gRPC-Web do navegador

Os aplicativos de navegador podem usar gRPC-Web para chamar serviços gRPC. Há alguns requisitos e limitações ao chamar serviços gRPC com gRPC-Web do navegador:

  • O servidor deve conter a configuração para dar suporte a gRPC-Web.
  • Não há suporte para chamadas a streaming de cliente e bidirecional. Há suporte para streaming de servidor.
  • Para chamar serviços gRPC em um domínio diferente, você precisa da configuração de CORS no servidor.

Cliente gRPC-Web em JavaScript

Há um cliente gRPC-Web em JavaScript. Para obter instruções sobre como usar gRPC-Web em JavaScript, confira Escrever código de cliente em JavaScript com gRPC-Web.

Configurar gRPC-Web com o cliente gRPC de .NET

O cliente gRPC de .NET pode ser configurado para fazer chamadas a gRPC-Web. Isso é útil para aplicativos Blazor WebAssembly, que são hospedados no navegador e têm as mesmas limitações de HTTP do código JavaScript. Chamar gRPC-Web com um cliente .NET é o mesmo que HTTP/2 gRPC. A única modificação é como o canal é criado.

Para usar gRPC-Web:

  • Adicione uma referência ao pacote Grpc.Net.Client.Web.
  • Verifique se a referência ao pacote Grpc.Net.Client é a versão 2.29.0 ou posterior.
  • Configure o canal para usar o GrpcWebHandler:
var channel = GrpcChannel.ForAddress("https://localhost:53305", new GrpcChannelOptions
{
    HttpHandler = new GrpcWebHandler(new HttpClientHandler())
});

var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(
                  new HelloRequest { Name = "GreeterClient" });

O código anterior:

  • Configura um canal para usar gRPC-Web.
  • Cria um cliente e faz uma chamada usando o canal .

GrpcWebHandler tem as seguintes opções de configuração:

  • InnerHandler: o HttpMessageHandler subjacente que faz a solicitação HTTP gRPC, por exemplo, HttpClientHandler.
  • GrpcWebMode: um tipo de enumeração que especifica se a solicitação HTTP gRPC Content-Type é application/grpc-web ou application/grpc-web-text.
    • GrpcWebMode.GrpcWeb configura o envio de conteúdo sem codificação. Valor padrão.
    • GrpcWebMode.GrpcWebText configura o conteúdo codificado em base64. Necessário para chamadas de streaming de servidor em navegadores.
  • HttpVersion: protocolo HTTP Version usado para definir HttpRequestMessage.Version na solicitação HTTP do gRPC subjacente. O gRPC-Web não requer uma versão específica e não substitui o padrão, a menos que especificado.

Importante

Os clientes gRPC gerados têm métodos síncronos e assíncronos para chamar métodos unários. Por exemplo, SayHello é síncrono e SayHelloAsync é assíncrono. Métodos assíncronos são sempre necessários em Blazor WebAssembly. Chamar um método síncrono em um aplicativo Blazor WebAssembly faz com que o aplicativo fique sem resposta.

Usar a fábrica de clientes gRPC com gRPC-Web

Crie um cliente .NET compatível com gRPC-Web usando a fábrica de clientes gRPC:

  • Adicione referências de pacote ao arquivo de projeto para os seguintes pacotes:
  • Registre um cliente gRPC com DI (injeção de dependência) usando o método de extensão genérico AddGrpcClient. Em um aplicativo Blazor WebAssembly, os serviços são registrados com DI no Program.cs.
  • Configure GrpcWebHandler usando o método de extensão ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Para saber mais, confira Integração de fábrica do cliente gRPC no .NET.

Recursos adicionais

Saiba como configurar um serviço gRPC ASP.NET Core existente para ser chamado de aplicativos de navegador, usando o protocolo gRPC-Web. O gRPC-Web permite que o JavaScript do navegador e os aplicativos Blazor chamem serviços gRPC. Não é possível chamar um serviço gRPC HTTP/2 de um aplicativo baseado em navegador. Os serviços gRPC hospedados em ASP.NET Core podem ser configurados para dar suporte a gRPC-Web junto com HTTP/2 gRPC.

Para obter instruções sobre como adicionar um serviço gRPC a um aplicativo ASP.NET Core existente, confira Adicionar serviços gRPC a um aplicativo ASP.NET Core.

Para obter instruções sobre como criar um projeto gRPC, confira Criar um cliente e um servidor gRPC do .NET Core no ASP.NET Core.

ASP.NET Core gRPC-Web versus Envoy

Há duas opções para adicionar gRPC-Web a um aplicativo ASP.NET Core:

  • Suporte a gRPC-Web junto com gRPC HTTP/2 em ASP.NET Core. Essa opção usa o middleware fornecido pelo pacote Grpc.AspNetCore.Web.
  • Use o suporte a gRPC-Web do proxy Envoy para converter gRPC-Web para gRPC HTTP/2. Em seguida, a chamada convertida é encaminhada para o aplicativo ASP.NET Core.

Há prós e contras em cada abordagem. Se o ambiente de um aplicativo já estiver usando o Envoy como proxy, talvez faça sentido também usar o Envoy para fornecer suporte a gRPC-Web. Para uma solução básica para gRPC-Web que requer apenas ASP.NET Core, Grpc.AspNetCore.Web é uma boa opção.

Configurar gRPC-Web no ASP.NET Core

Os serviços gRPC hospedados em ASP.NET Core podem ser configurados para dar suporte a gRPC-Web junto com HTTP/2 gRPC. O gRPC-Web não exige nenhuma alteração nos serviços. A única modificação é a configuração de inicialização.

Para habilitar o gRPC-Web com um serviço gRPC ASP.NET Core:

  • Adicione uma referência ao pacote Grpc.AspNetCore.Web.
  • Configure o aplicativo para usar gRPC-Web adicionando UseGrpcWeb e EnableGrpcWeb a Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseGrpcWeb(); // Must be added between UseRouting and UseEndpoints

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();
    });
}

O código anterior:

  • Adiciona o middleware gRPC-Web, UseGrpcWeb, após o roteamento e antes dos pontos de extremidade.
  • Especifica que o método endpoints.MapGrpcService<GreeterService>() dá suporte a gRPC-Web com EnableGrpcWeb.

Como alternativa, o middleware gRPC-Web pode ser configurado para que todos os serviços ofereçam suporte a gRPC-Web por padrão e para que EnableGrpcWeb não seja necessário. Especifique new GrpcWebOptions { DefaultEnabled = true } quando o middleware for adicionado.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<GreeterService>();
        });
    }
}

Observação

Há um problema conhecido que faz com que o gRPC-Web falhe quando hospedado por HTTP.sys no .NET Core 3.x.

Uma solução alternativa para fazer com que o gRPC-Web funcione no HTTP.sys está disponível em Grpc-web experimental e UseHttpSys()? (grpc/grpc-dotnet #853).

gRPC-Web e CORS

A segurança do navegador impede que uma página da Web faça solicitações para um domínio diferente daquele que ofereceu a página da Web. Essa restrição se aplica à realização de chamadas gRPC-Web com aplicativos de navegador. Por exemplo, um aplicativo de navegador oferecido por https://www.contoso.com fica impedido de chamar serviços gRPC-Web hospedados em https://services.contoso.com. O CORS (Compartilhamento de Recursos entre Origens) pode ser usado para afrouxar essa restrição.

Para permitir que um aplicativo de navegador faça chamadas gRPC-Web entre origens, configure o CORS no ASP.NET Core. Use o suporte interno ao CORS e exponha cabeçalhos específicos do gRPC com WithExposedHeaders.

public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();

    services.AddCors(o => o.AddPolicy("AllowAll", builder =>
    {
        builder.AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader()
               .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
    }));
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseGrpcWeb();
    app.UseCors();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb()
                                                  .RequireCors("AllowAll");
    });
}

O código anterior:

  • Chama AddCors para adicionar serviços CORS e configurar uma política CORS que expõe cabeçalhos específicos ao gRPC.
  • Chama UseCors para adicionar o middleware CORS após a configuração de roteamento e antes da configuração dos pontos de extremidade.
  • Especifica que o método endpoints.MapGrpcService<GreeterService>() dá suporte a gRPC-Web com RequireCors.

gRPC-Web e streaming

O gRPC tradicional por HTTP/2 dá suporte a streaming de cliente, servidor e bidirecional. O gRPC-Web oferece suporte limitado para streaming:

  • Os clientes do navegador gRPC-Web não dão suporte à chamada de métodos de streaming de cliente e bidirecional.
  • Os clientes .NET de gRPC-Web não dão suporte à chamada de métodos de streaming de cliente e bidirecional sobre HTTP/1.1.
  • ASP.NET Core serviços gRPC hospedados no Serviço de Aplicativo do Azure e o IIS não dão suporte ao streaming bidirecional.

Ao usar gRPC-Web, recomendamos apenas o uso de métodos unários e métodos de streaming de servidor.

Protocolo HTTP

O modelo de serviço gRPC do ASP.NET Core, incluído no SDK do .NET, cria um aplicativo configurado apenas para HTTP/2. Isso é um bom padrão quando um aplicativo dá suporte apenas ao gRPC tradicional por HTTP/2. O gRPC-Web, no entanto, funciona com HTTP/1.1 e HTTP/2. Algumas plataformas, como UWP ou Unity, não podem usar HTTP/2. Para dar suporte a todos os aplicativos cliente, configure o servidor para habilitar HTTP/1.1 e HTTP/2.

Atualize o protocolo padrão em appsettings.json:

{
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http1AndHttp2"
    }
  }
}

Como alternativa, configure pontos de extremidade Kestrel no código de inicialização.

A habilitação de HTTP/1.1 e HTTP/2 na mesma porta exige TLS para negociação de protocolo. Para obter mais informações, confira Negociação de protocolo gRPC do ASP.NET Core.

Chamar gRPC-Web do navegador

Os aplicativos de navegador podem usar gRPC-Web para chamar serviços gRPC. Há alguns requisitos e limitações ao chamar serviços gRPC com gRPC-Web do navegador:

  • O servidor deve conter a configuração para dar suporte a gRPC-Web.
  • Não há suporte para chamadas a streaming de cliente e bidirecional. Há suporte para streaming de servidor.
  • Para chamar serviços gRPC em um domínio diferente, você precisa da configuração de CORS no servidor.

Cliente gRPC-Web em JavaScript

Há um cliente gRPC-Web em JavaScript. Para obter instruções sobre como usar gRPC-Web em JavaScript, confira Escrever código de cliente em JavaScript com gRPC-Web.

Configurar gRPC-Web com o cliente gRPC de .NET

O cliente gRPC de .NET pode ser configurado para fazer chamadas a gRPC-Web. Isso é útil para aplicativos Blazor WebAssembly, que são hospedados no navegador e têm as mesmas limitações de HTTP do código JavaScript. Chamar gRPC-Web com um cliente .NET é o mesmo que HTTP/2 gRPC. A única modificação é como o canal é criado.

Para usar gRPC-Web:

  • Adicione uma referência ao pacote Grpc.Net.Client.Web.
  • Verifique se a referência ao pacote Grpc.Net.Client é a versão 2.29.0 ou posterior.
  • Configure o canal para usar o GrpcWebHandler:
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
    {
        HttpHandler = new GrpcWebHandler(new HttpClientHandler())
    });

var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

O código anterior:

  • Configura um canal para usar gRPC-Web.
  • Cria um cliente e faz uma chamada usando o canal .

GrpcWebHandler tem as seguintes opções de configuração:

  • InnerHandler: o HttpMessageHandler subjacente que faz a solicitação HTTP gRPC, por exemplo, HttpClientHandler.
  • GrpcWebMode: um tipo de enumeração que especifica se a solicitação HTTP gRPC Content-Type é application/grpc-web ou application/grpc-web-text.
    • GrpcWebMode.GrpcWeb configura o envio de conteúdo sem codificação. Valor padrão.
    • GrpcWebMode.GrpcWebText configura o conteúdo codificado em base64. Necessário para chamadas de streaming de servidor em navegadores.
  • HttpVersion: protocolo HTTP Version usado para definir HttpRequestMessage.Version na solicitação HTTP do gRPC subjacente. O gRPC-Web não requer uma versão específica e não substitui o padrão, a menos que especificado.

Importante

Os clientes gRPC gerados têm métodos síncronos e assíncronos para chamar métodos unários. Por exemplo, SayHello é síncrono e SayHelloAsync é assíncrono. Métodos assíncronos são sempre necessários em Blazor WebAssembly. Chamar um método síncrono em um aplicativo Blazor WebAssembly faz com que o aplicativo fique sem resposta.

Usar a fábrica de clientes gRPC com gRPC-Web

Crie um cliente .NET compatível com gRPC-Web usando a fábrica de clientes gRPC:

  • Adicione referências de pacote ao arquivo de projeto para os seguintes pacotes:
  • Registre um cliente gRPC com DI (injeção de dependência) usando o método de extensão genérico AddGrpcClient. Em um aplicativo Blazor WebAssembly, os serviços são registrados com DI no Program.cs.
  • Configure GrpcWebHandler usando o método de extensão ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Para saber mais, confira Integração de fábrica do cliente gRPC no .NET.

Recursos adicionais