gRPC-Web en aplicaciones gRPC de ASP.NET Core

Por James Newton-King

Obtenga información sobre cómo configurar un servicio gRPC de ASP.NET Core existente al que se puede llamar desde aplicaciones del explorador mediante el protocolo gRPC-Web. gRPC-Web permite a las aplicaciones de explorador de JavaScript y Blazor llamar a servicios gRPC. No se puede llamar a un servicio HTTP/2 gRPC desde una aplicación basada en el explorador. Los servicios gRPC hospedados en ASP.NET Core se pueden configurar para admitir gRPC-Web junto con HTTP/2 gRPC.

Para instrucciones sobre cómo agregar un servicio gRPC a una aplicación de ASP.NET Core existente, consulte Incorporación de servicios gRPC a una aplicación de ASP.NET Core.

Para obtener instrucciones sobre cómo crear un proyecto gRPC, consulte Creación de un servidor y un cliente gRPC en ASP.NET Core.

gRPC-Web de ASP.NET Core frente a Envoy

Hay dos opciones para agregar gRPC-Web a una aplicación de ASP.NET Core:

  • Compatibilidad con gRPC-Web junto con HTTP/2 gRPC en ASP.NET Core. Esta opción usa el middleware que el paquete Grpc.AspNetCore.Web proporciona.
  • Use la compatibilidad con gRPC-Web del proxy de Envoy para traducir gRPC-Web a HTTP/2 gRPC. A continuación, la llamada traducida se reenvía a la aplicación ASP.NET Core.

Cada enfoque tiene ventajas y desventajas. Si el entorno de una aplicación ya usa Envoy como proxy, puede que tenga sentido usar Envoy para proporcionar compatibilidad con gRPC-Web. Para obtener una solución básica para gRPC-Web que solo requiera ASP.NET Core, Grpc.AspNetCore.Web es una buena elección.

Configuración de gRPC-Web en ASP.NET Core

Los servicios gRPC hospedados en ASP.NET Core se pueden configurar para admitir gRPC-Web junto con HTTP/2 gRPC. gRPC-Web no requiere ningún cambio en los servicios. La única modificación consiste en establecer el middleware en Program.cs.

Para habilitar gRPC-Web con un servicio gRPC de ASP.NET Core:

  • Agregar una referencia al paquete Grpc.AspNetCore.Web.
  • Configure la aplicación para que use gRPC-Web, agregando para ello UseGrpcWeb y 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();

El código anterior:

  • Agrega el middleware de gRPC-Web, UseGrpcWeb, después del enrutamiento y antes de los puntos de conexión.
  • Especifica que el método endpoints.MapGrpcService<GreeterService>() admite gRPC-Web con EnableGrpcWeb.

Como alternativa, se puede configurar el middleware gRPC-Web de forma que todos los servicios admitan gRPC-Web de forma predeterminada y no se necesite EnableGrpcWeb. Especifique new GrpcWebOptions { DefaultEnabled = true } cuando se agregue el middleware.

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

Nota

Hay un problema conocido que hace que gRPC-Web genere un error cuando está hospedado en HTTP.sys en .NET Core 3.x.

Hay disponible una solución alternativa para que gRPC-Web funcione en HTTP.sys en Grpc-web experimental y UseHttpSys()? (grpc/grpc-dotnet #853).

gRPC-Web y CORS

La seguridad del explorador evita que una página web realice solicitudes a un dominio diferente del que atendió a dicha página web. Esta restricción se aplica a la hora de realizar llamadas de gRPC-Web con aplicaciones de explorador. Por ejemplo, una aplicación de explorador atendida por https://www.contoso.com no puede llamar a los servicios gRPC-Web hospedados en https://services.contoso.com. Para suavizar esta restricción, podemos recurrir al uso compartido de recursos entre orígenes (CORS).

Para permitir que una aplicación de explorador haga llamadas de gRPC-Web entre orígenes, configure CORS en ASP.NET Core. Use la compatibilidad de CORS integrada y exponga los encabezados específicos de gRPC con 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();

El código anterior:

  • Llama a AddCors para agregar los servicios CORS y configura una directiva CORS que expone los encabezados específicos de gRPC.
  • Llama a UseCors para agregar el middleware de CORS después de la configuración del enrutamiento y antes de la configuración de los puntos de conexión.
  • Especifica que el método endpoints.MapGrpcService<GreeterService>() admite CORS con RequireCors.

gRPC-Web y streaming

GRPC tradicional a través de HTTP/2 admite el streaming de cliente, servidor y bidireccional. gRPC-Web ofrece compatibilidad limitada para streaming:

  • Los clientes del explorador gRPC-Web no admiten la llamada a métodos de streaming de cliente y streaming bidireccional.
  • Los clientes de .NET de gRPC-Web no admiten la llamada a métodos de streaming de cliente y streaming bidireccional a través de HTTP/1.1.
  • Los servicios gRPC de ASP.NET Core hospedados en Azure App Service e IIS no admiten streaming bidireccional.

Al usar gRPC-Web, solo se recomienda el uso de métodos unarios y métodos de streaming de servidor.

Protocolo HTTP

La plantilla de servicio gRPC de ASP.NET Core, incluida en el SDK de .NET, crea una aplicación que solo está configurada para HTTP/2. Este es un buen valor predeterminado cuando una aplicación solo admite gRPC tradicional a través de HTTP/2. Sin embargo, gRPC-Web funciona con HTTP/1.1 y HTTP/2. Algunas plataformas, como UWP o Unity, no pueden usar HTTP/2. Para admitir todas las aplicaciones cliente, configure el servidor para habilitar HTTP/1.1 y HTTP/2.

Actualice el protocolo predeterminado en appsettings.json:

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

Como alternativa, configure los puntos de conexión de Kestrel en el código de inicio.

La habilitación de HTTP/1.1 y HTTP/2 en el mismo puerto requiere TLS para la negociación de protocolos. Para más información, consulte Negociación de protocolos de gRPC en ASP.NET Core.

Llamada a gRPC-Web desde el explorador

Las aplicaciones de explorador pueden usar gRPC-Web para llamar a servicios gRPC. Existen algunos requisitos y limitaciones a la hora de llamar a servicios gRPC con gRPC-Web desde el explorador:

  • El servidor debe contener la configuración para admitir gRPC-Web.
  • No se pueden usar llamadas de streaming de cliente ni de streaming bidireccional. Sí se puede usar el streaming de servidor.
  • Para llamar a servicios gRPC en otro dominio, hay que configurar CORS en el servidor.

Cliente gRPC-Web de JavaScript

Existe un cliente gRPC-Web de JavaScript. Para obtener instrucciones sobre cómo usar gRPC-Web en JavaScript, vea Escribir código de cliente de JavaScript con gRPC-Web.

Configuración de gRPC-Web con el cliente gRPC de .NET

El cliente gRPC de .NET se puede configurar para realizar llamadas de gRPC-Web. Esto resulta útil en las aplicaciones Blazor WebAssembly, que se hospedan en el explorador y tienen las mismas limitaciones HTTP de código JavaScript. Llamar a gRPC-Web con un cliente .NET es igual que HTTP/2 gRPC. La única modificación es cómo se crea el canal.

Para usar gRPC-Web:

  • Agregar una referencia al paquete Grpc.Net.Client.Web.
  • Asegúrese de que la referencia al paquete Grpc.Net.Client sea la versión 2.29.0 o posterior.
  • Configure el canal para que use 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" });

El código anterior:

  • Configura un canal para que use gRPC-Web.
  • Crea un cliente y realiza una llamada usando el canal.

GrpcWebHandler tiene las siguientes opciones de configuración:

  • InnerHandlerInnerHandler: elemento InnerHandler subyacente que realiza la solicitud HTTP de gRPC, por ejemplo, HttpClientHandler.
  • GrpcWebModeGrpcWebMode: tipo de enumeración que especifica si el elemento GrpcWebMode de la solicitud HTTP de gRPC es application/grpc-web o application/grpc-web-text.
    • GrpcWebMode.GrpcWeb configura el envío de contenido sin codificación. Valor predeterminado.
    • GrpcWebMode.GrpcWebText configura el contenido codificado en Base64. Esto es necesario en las llamadas de streaming de servidor en los exploradores.
  • HttpVersionHttpVersion: elemento HttpVersion del protocolo HTTP que se usa para establecer HttpRequestMessage.VersionHttpRequestMessage.Version en la solicitud HTTP de gRPC subyacente. gRPC-Web no requiere que haya una versión específica y no invalida el valor predeterminado a menos que así se especifique.

Importante

Los clientes de gRPC generados tienen métodos sincrónicos y asincrónicos para llamar a métodos unarios. Por ejemplo, SayHello es sincrónico y SayHelloAsync es asincrónico. Los métodos asincrónicos siempre son necesarios en Blazor WebAssembly. La llamada a un método sincrónico en una aplicación Blazor WebAssembly provoca que la aplicación deje de responder.

Uso de la fábrica de cliente gRPC con gRPC-Web

Cree un cliente .NET compatible con gRPC-Web mediante el generador de cliente gRPC:

  • Agregue referencias de paquete al archivo del proyecto para los paquetes siguientes:
  • Registre un cliente de gRPC con inserción de dependencias mediante el método de extensión genérico AddGrpcClient. En una aplicación Blazor WebAssembly, los servicios se registran con la inserción de dependencias en Program.cs.
  • Configure GrpcWebHandler mediante el método de extensión ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Para más información, consulte Integración de la fábrica de cliente de gRPC en .NET.

Recursos adicionales

Obtenga información sobre cómo configurar un servicio gRPC de ASP.NET Core existente al que se puede llamar desde aplicaciones del explorador mediante el protocolo gRPC-Web. gRPC-Web permite a las aplicaciones de explorador de JavaScript y Blazor llamar a servicios gRPC. No se puede llamar a un servicio HTTP/2 gRPC desde una aplicación basada en el explorador. Los servicios gRPC hospedados en ASP.NET Core se pueden configurar para admitir gRPC-Web junto con HTTP/2 gRPC.

Para instrucciones sobre cómo agregar un servicio gRPC a una aplicación de ASP.NET Core existente, consulte Incorporación de servicios gRPC a una aplicación de ASP.NET Core.

Para obtener instrucciones sobre cómo crear un proyecto gRPC, consulte Creación de un servidor y un cliente gRPC en ASP.NET Core.

gRPC-Web de ASP.NET Core frente a Envoy

Hay dos opciones para agregar gRPC-Web a una aplicación de ASP.NET Core:

  • Compatibilidad con gRPC-Web junto con HTTP/2 gRPC en ASP.NET Core. Esta opción usa el middleware que el paquete Grpc.AspNetCore.Web proporciona.
  • Use la compatibilidad con gRPC-Web del proxy de Envoy para traducir gRPC-Web a HTTP/2 gRPC. A continuación, la llamada traducida se reenvía a la aplicación ASP.NET Core.

Cada enfoque tiene ventajas y desventajas. Si el entorno de una aplicación ya usa Envoy como proxy, puede que tenga sentido usar Envoy para proporcionar compatibilidad con gRPC-Web. Para obtener una solución básica para gRPC-Web que solo requiera ASP.NET Core, Grpc.AspNetCore.Web es una buena elección.

Configuración de gRPC-Web en ASP.NET Core

Los servicios gRPC hospedados en ASP.NET Core se pueden configurar para admitir gRPC-Web junto con HTTP/2 gRPC. gRPC-Web no requiere ningún cambio en los servicios. La única modificación consiste en establecer el middleware en Program.cs.

Para habilitar gRPC-Web con un servicio gRPC de ASP.NET Core:

  • Agregar una referencia al paquete Grpc.AspNetCore.Web.
  • Configure la aplicación para que use gRPC-Web, agregando para ello UseGrpcWeb y 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();

El código anterior:

  • Agrega el middleware de gRPC-Web, UseGrpcWeb, después del enrutamiento y antes de los puntos de conexión.
  • Especifica que el método endpoints.MapGrpcService<GreeterService>() admite gRPC-Web con EnableGrpcWeb.

Como alternativa, se puede configurar el middleware gRPC-Web de forma que todos los servicios admitan gRPC-Web de forma predeterminada y no se necesite EnableGrpcWeb. Especifique new GrpcWebOptions { DefaultEnabled = true } cuando se agregue el middleware.

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

Nota

Hay un problema conocido que hace que gRPC-Web genere un error cuando está hospedado en HTTP.sys en .NET Core 3.x.

Hay disponible una solución alternativa para que gRPC-Web funcione en HTTP.sys en Grpc-web experimental y UseHttpSys()? (grpc/grpc-dotnet #853).

gRPC-Web y CORS

La seguridad del explorador evita que una página web realice solicitudes a un dominio diferente del que atendió a dicha página web. Esta restricción se aplica a la hora de realizar llamadas de gRPC-Web con aplicaciones de explorador. Por ejemplo, una aplicación de explorador atendida por https://www.contoso.com no puede llamar a los servicios gRPC-Web hospedados en https://services.contoso.com. Para suavizar esta restricción, podemos recurrir al uso compartido de recursos entre orígenes (CORS).

Para permitir que una aplicación de explorador haga llamadas de gRPC-Web entre orígenes, configure CORS en ASP.NET Core. Use la compatibilidad de CORS integrada y exponga los encabezados específicos de gRPC con 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();

El código anterior:

  • Llama a AddCors para agregar los servicios CORS y configura una directiva CORS que expone los encabezados específicos de gRPC.
  • Llama a UseCors para agregar el middleware de CORS después de la configuración del enrutamiento y antes de la configuración de los puntos de conexión.
  • Especifica que el método endpoints.MapGrpcService<GreeterService>() admite CORS con RequireCors.

gRPC-Web y streaming

GRPC tradicional a través de HTTP/2 admite el streaming de cliente, servidor y bidireccional. gRPC-Web ofrece compatibilidad limitada para streaming:

  • Los clientes del explorador gRPC-Web no admiten la llamada a métodos de streaming de cliente y streaming bidireccional.
  • Los clientes de .NET de gRPC-Web no admiten la llamada a métodos de streaming de cliente y streaming bidireccional a través de HTTP/1.1.
  • Los servicios gRPC de ASP.NET Core hospedados en Azure App Service e IIS no admiten streaming bidireccional.

Al usar gRPC-Web, solo se recomienda el uso de métodos unarios y métodos de streaming de servidor.

Protocolo HTTP

La plantilla de servicio gRPC de ASP.NET Core, incluida en el SDK de .NET, crea una aplicación que solo está configurada para HTTP/2. Este es un buen valor predeterminado cuando una aplicación solo admite gRPC tradicional a través de HTTP/2. Sin embargo, gRPC-Web funciona con HTTP/1.1 y HTTP/2. Algunas plataformas, como UWP o Unity, no pueden usar HTTP/2. Para admitir todas las aplicaciones cliente, configure el servidor para habilitar HTTP/1.1 y HTTP/2.

Actualice el protocolo predeterminado en appsettings.json:

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

Como alternativa, configure los puntos de conexión de Kestrel en el código de inicio.

La habilitación de HTTP/1.1 y HTTP/2 en el mismo puerto requiere TLS para la negociación de protocolos. Para más información, consulte Negociación de protocolos de gRPC en ASP.NET Core.

Llamada a gRPC-Web desde el explorador

Las aplicaciones de explorador pueden usar gRPC-Web para llamar a servicios gRPC. Existen algunos requisitos y limitaciones a la hora de llamar a servicios gRPC con gRPC-Web desde el explorador:

  • El servidor debe contener la configuración para admitir gRPC-Web.
  • No se pueden usar llamadas de streaming de cliente ni de streaming bidireccional. Sí se puede usar el streaming de servidor.
  • Para llamar a servicios gRPC en otro dominio, hay que configurar CORS en el servidor.

Cliente gRPC-Web de JavaScript

Existe un cliente gRPC-Web de JavaScript. Para obtener instrucciones sobre cómo usar gRPC-Web en JavaScript, vea Escribir código de cliente de JavaScript con gRPC-Web.

Configuración de gRPC-Web con el cliente gRPC de .NET

El cliente gRPC de .NET se puede configurar para realizar llamadas de gRPC-Web. Esto resulta útil en las aplicaciones Blazor WebAssembly, que se hospedan en el explorador y tienen las mismas limitaciones HTTP de código JavaScript. Llamar a gRPC-Web con un cliente .NET es igual que HTTP/2 gRPC. La única modificación es cómo se crea el canal.

Para usar gRPC-Web:

  • Agregar una referencia al paquete Grpc.Net.Client.Web.
  • Asegúrese de que la referencia al paquete Grpc.Net.Client sea la versión 2.29.0 o posterior.
  • Configure el canal para que use 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" });

El código anterior:

  • Configura un canal para que use gRPC-Web.
  • Crea un cliente y realiza una llamada usando el canal.

GrpcWebHandler tiene las siguientes opciones de configuración:

  • InnerHandlerInnerHandler: elemento InnerHandler subyacente que realiza la solicitud HTTP de gRPC, por ejemplo, HttpClientHandler.
  • GrpcWebModeGrpcWebMode: tipo de enumeración que especifica si el elemento GrpcWebMode de la solicitud HTTP de gRPC es application/grpc-web o application/grpc-web-text.
    • GrpcWebMode.GrpcWeb configura el envío de contenido sin codificación. Valor predeterminado.
    • GrpcWebMode.GrpcWebText configura el contenido codificado en Base64. Esto es necesario en las llamadas de streaming de servidor en los exploradores.
  • HttpVersionHttpVersion: elemento HttpVersion del protocolo HTTP que se usa para establecer HttpRequestMessage.VersionHttpRequestMessage.Version en la solicitud HTTP de gRPC subyacente. gRPC-Web no requiere que haya una versión específica y no invalida el valor predeterminado a menos que así se especifique.

Importante

Los clientes de gRPC generados tienen métodos sincrónicos y asincrónicos para llamar a métodos unarios. Por ejemplo, SayHello es sincrónico y SayHelloAsync es asincrónico. Los métodos asincrónicos siempre son necesarios en Blazor WebAssembly. La llamada a un método sincrónico en una aplicación Blazor WebAssembly provoca que la aplicación deje de responder.

Uso de la fábrica de cliente gRPC con gRPC-Web

Cree un cliente .NET compatible con gRPC-Web mediante el generador de cliente gRPC:

  • Agregue referencias de paquete al archivo del proyecto para los paquetes siguientes:
  • Registre un cliente de gRPC con inserción de dependencias mediante el método de extensión genérico AddGrpcClient. En una aplicación Blazor WebAssembly, los servicios se registran con la inserción de dependencias en Program.cs.
  • Configure GrpcWebHandler mediante el método de extensión ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Para más información, consulte Integración de la fábrica de cliente de gRPC en .NET.

Recursos adicionales

Obtenga información sobre cómo configurar un servicio gRPC de ASP.NET Core existente al que se puede llamar desde aplicaciones del explorador mediante el protocolo gRPC-Web. gRPC-Web permite a las aplicaciones de explorador de JavaScript y Blazor llamar a servicios gRPC. No se puede llamar a un servicio HTTP/2 gRPC desde una aplicación basada en el explorador. Los servicios gRPC hospedados en ASP.NET Core se pueden configurar para admitir gRPC-Web junto con HTTP/2 gRPC.

Para instrucciones sobre cómo agregar un servicio gRPC a una aplicación de ASP.NET Core existente, consulte Incorporación de servicios gRPC a una aplicación de ASP.NET Core.

Para obtener instrucciones sobre cómo crear un proyecto gRPC, consulte Creación de un servidor y un cliente gRPC en ASP.NET Core.

gRPC-Web de ASP.NET Core frente a Envoy

Hay dos opciones para agregar gRPC-Web a una aplicación de ASP.NET Core:

  • Compatibilidad con gRPC-Web junto con HTTP/2 gRPC en ASP.NET Core. Esta opción usa el middleware que el paquete Grpc.AspNetCore.Web proporciona.
  • Use la compatibilidad con gRPC-Web del proxy de Envoy para traducir gRPC-Web a HTTP/2 gRPC. A continuación, la llamada traducida se reenvía a la aplicación ASP.NET Core.

Cada enfoque tiene ventajas y desventajas. Si el entorno de una aplicación ya usa Envoy como proxy, puede que tenga sentido usar Envoy para proporcionar compatibilidad con gRPC-Web. Para obtener una solución básica para gRPC-Web que solo requiera ASP.NET Core, Grpc.AspNetCore.Web es una buena elección.

Configuración de gRPC-Web en ASP.NET Core

Los servicios gRPC hospedados en ASP.NET Core se pueden configurar para admitir gRPC-Web junto con HTTP/2 gRPC. gRPC-Web no requiere ningún cambio en los servicios. La única modificación es la configuración de inicio.

Para habilitar gRPC-Web con un servicio gRPC de ASP.NET Core:

  • Agregar una referencia al paquete Grpc.AspNetCore.Web.
  • Configure la aplicación para que use gRPC-Web, agregando para ello UseGrpcWeb y 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();
    });
}

El código anterior:

  • Agrega el middleware de gRPC-Web, UseGrpcWeb, después del enrutamiento y antes de los puntos de conexión.
  • Especifica que el método endpoints.MapGrpcService<GreeterService>() admite gRPC-Web con EnableGrpcWeb.

Como alternativa, se puede configurar el middleware gRPC-Web de forma que todos los servicios admitan gRPC-Web de forma predeterminada y no se necesite EnableGrpcWeb. Especifique new GrpcWebOptions { DefaultEnabled = true } cuando se agregue el middleware.

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

Nota

Hay un problema conocido que hace que gRPC-Web genere un error cuando está hospedado en HTTP.sys en .NET Core 3.x.

Hay disponible una solución alternativa para que gRPC-Web funcione en HTTP.sys en Grpc-web experimental y UseHttpSys()? (grpc/grpc-dotnet #853).

gRPC-Web y CORS

La seguridad del explorador evita que una página web realice solicitudes a un dominio diferente del que atendió a dicha página web. Esta restricción se aplica a la hora de realizar llamadas de gRPC-Web con aplicaciones de explorador. Por ejemplo, una aplicación de explorador atendida por https://www.contoso.com no puede llamar a los servicios gRPC-Web hospedados en https://services.contoso.com. Para suavizar esta restricción, podemos recurrir al uso compartido de recursos entre orígenes (CORS).

Para permitir que una aplicación de explorador haga llamadas de gRPC-Web entre orígenes, configure CORS en ASP.NET Core. Use la compatibilidad de CORS integrada y exponga los encabezados específicos de gRPC con 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");
    });
}

El código anterior:

  • Llama a AddCors para agregar los servicios CORS y configura una directiva CORS que expone los encabezados específicos de gRPC.
  • Llama a UseCors para agregar el middleware de CORS después de la configuración del enrutamiento y antes de la configuración de los puntos de conexión.
  • Especifica que el método endpoints.MapGrpcService<GreeterService>() admite CORS con RequireCors.

gRPC-Web y streaming

GRPC tradicional a través de HTTP/2 admite el streaming de cliente, servidor y bidireccional. gRPC-Web ofrece compatibilidad limitada para streaming:

  • Los clientes del explorador gRPC-Web no admiten la llamada a métodos de streaming de cliente y streaming bidireccional.
  • Los clientes de .NET de gRPC-Web no admiten la llamada a métodos de streaming de cliente y streaming bidireccional a través de HTTP/1.1.
  • Los servicios gRPC de ASP.NET Core hospedados en Azure App Service e IIS no admiten streaming bidireccional.

Al usar gRPC-Web, solo se recomienda el uso de métodos unarios y métodos de streaming de servidor.

Protocolo HTTP

La plantilla de servicio gRPC de ASP.NET Core, incluida en el SDK de .NET, crea una aplicación que solo está configurada para HTTP/2. Este es un buen valor predeterminado cuando una aplicación solo admite gRPC tradicional a través de HTTP/2. Sin embargo, gRPC-Web funciona con HTTP/1.1 y HTTP/2. Algunas plataformas, como UWP o Unity, no pueden usar HTTP/2. Para admitir todas las aplicaciones cliente, configure el servidor para habilitar HTTP/1.1 y HTTP/2.

Actualice el protocolo predeterminado en appsettings.json:

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

Como alternativa, configure los puntos de conexión de Kestrel en el código de inicio.

La habilitación de HTTP/1.1 y HTTP/2 en el mismo puerto requiere TLS para la negociación de protocolos. Para más información, consulte Negociación de protocolos de gRPC en ASP.NET Core.

Llamada a gRPC-Web desde el explorador

Las aplicaciones de explorador pueden usar gRPC-Web para llamar a servicios gRPC. Existen algunos requisitos y limitaciones a la hora de llamar a servicios gRPC con gRPC-Web desde el explorador:

  • El servidor debe contener la configuración para admitir gRPC-Web.
  • No se pueden usar llamadas de streaming de cliente ni de streaming bidireccional. Sí se puede usar el streaming de servidor.
  • Para llamar a servicios gRPC en otro dominio, hay que configurar CORS en el servidor.

Cliente gRPC-Web de JavaScript

Existe un cliente gRPC-Web de JavaScript. Para obtener instrucciones sobre cómo usar gRPC-Web en JavaScript, vea Escribir código de cliente de JavaScript con gRPC-Web.

Configuración de gRPC-Web con el cliente gRPC de .NET

El cliente gRPC de .NET se puede configurar para realizar llamadas de gRPC-Web. Esto resulta útil en las aplicaciones Blazor WebAssembly, que se hospedan en el explorador y tienen las mismas limitaciones HTTP de código JavaScript. Llamar a gRPC-Web con un cliente .NET es igual que HTTP/2 gRPC. La única modificación es cómo se crea el canal.

Para usar gRPC-Web:

  • Agregar una referencia al paquete Grpc.Net.Client.Web.
  • Asegúrese de que la referencia al paquete Grpc.Net.Client sea la versión 2.29.0 o posterior.
  • Configure el canal para que use 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" });

El código anterior:

  • Configura un canal para que use gRPC-Web.
  • Crea un cliente y realiza una llamada usando el canal.

GrpcWebHandler tiene las siguientes opciones de configuración:

  • InnerHandlerInnerHandler: elemento InnerHandler subyacente que realiza la solicitud HTTP de gRPC, por ejemplo, HttpClientHandler.
  • GrpcWebModeGrpcWebMode: tipo de enumeración que especifica si el elemento GrpcWebMode de la solicitud HTTP de gRPC es application/grpc-web o application/grpc-web-text.
    • GrpcWebMode.GrpcWeb configura el envío de contenido sin codificación. Valor predeterminado.
    • GrpcWebMode.GrpcWebText configura el contenido codificado en Base64. Esto es necesario en las llamadas de streaming de servidor en los exploradores.
  • HttpVersionHttpVersion: elemento HttpVersion del protocolo HTTP que se usa para establecer HttpRequestMessage.VersionHttpRequestMessage.Version en la solicitud HTTP de gRPC subyacente. gRPC-Web no requiere que haya una versión específica y no invalida el valor predeterminado a menos que así se especifique.

Importante

Los clientes de gRPC generados tienen métodos sincrónicos y asincrónicos para llamar a métodos unarios. Por ejemplo, SayHello es sincrónico y SayHelloAsync es asincrónico. Los métodos asincrónicos siempre son necesarios en Blazor WebAssembly. La llamada a un método sincrónico en una aplicación Blazor WebAssembly provoca que la aplicación deje de responder.

Uso de la fábrica de cliente gRPC con gRPC-Web

Cree un cliente .NET compatible con gRPC-Web mediante el generador de cliente gRPC:

  • Agregue referencias de paquete al archivo del proyecto para los paquetes siguientes:
  • Registre un cliente de gRPC con inserción de dependencias mediante el método de extensión genérico AddGrpcClient. En una aplicación Blazor WebAssembly, los servicios se registran con la inserción de dependencias en Program.cs.
  • Configure GrpcWebHandler mediante el método de extensión ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Para más información, consulte Integración de la fábrica de cliente de gRPC en .NET.

Recursos adicionales