Transcodificación JSON de gRPC en ASP.NET Core

Por James Newton-King

gRPC es un marco de llamada a procedimiento remoto (RPC) de alto rendimiento. gRPC usa HTTP/2, streaming, Protobuf y contratos de mensaje para crear servicios en tiempo real de alto rendimiento.

Una limitación de gRPC es que no se puede usar en todas las plataformas. Los exploradores no son totalmente compatibles con HTTP/2, por lo que las API REST y JSON son la manera principal de obtener datos en aplicaciones de explorador. Incluso con las ventajas que aporta gRPC, las API REST y JSON ocupan un lugar importante en las aplicaciones modernas. La compilación de API web JSON y gRPC agrega una sobrecarga no deseada al desarrollo de aplicaciones.

En este documento se explica cómo crear API web JSON con servicios gRPC.

Información general

La transcodificación JSON de gRPC es una extensión para ASP.NET Core que crea API JSON de RESTful para servicios gRPC. Una vez configurada, la transcodificación permite que las aplicaciones llamen a servicios gRPC con conceptos conocidos de HTTP:

  • Verbos HTTP
  • Enlace de parámetros de dirección URL
  • Solicitudes y respuestas JSON

gRPC también se puede usar para llamar a servicios.

Nota

La transcodificación JSON de gRPC reemplaza la API HTTP de gRPC, una extensión experimental alternativa.

Uso

  1. Agregue una referencia de paquete a Microsoft.AspNetCore.Grpc.JsonTranscoding.

  2. Registre la transcodificación en el código de inicio del servidor agregando AddJsonTranscoding: en el archivo Program.cs, cambie builder.Services.AddGrpc(); por builder.Services.AddGrpc().AddJsonTranscoding();.

  3. Agregue <IncludeHttpRuleProtos>true</IncludeHttpRuleProtos> al grupo de propiedades en el archivo de proyecto (.csproj):

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
      <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <InvariantGlobalization>true</InvariantGlobalization>
        <IncludeHttpRuleProtos>true</IncludeHttpRuleProtos>
      </PropertyGroup>
    
  4. Anote los métodos gRPC en los archivos .proto con enlaces y rutas HTTP:

    syntax = "proto3";
    
    option csharp_namespace = "GrpcServiceTranscoding";
    import "google/api/annotations.proto";
    
    package greet;
    
    // The greeting service definition.
    service Greeter {
      rpc SayHello (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
          get: "/v1/greeter/{name}"
        };
      }
    }
    
    // The request message containing the user's name.
    message HelloRequest {
      string name = 1;
    }
    
    // The response message containing the greetings.
    message HelloReply {
      string message = 1;
    }
    

El método gRPC SayHello ya se puede invocar como gRPC y como una API web de JSON:

  • Solicitud: GET /v1/greeter/world
  • Respuesta: { "message": "Hello world" }

Si el servidor está configurado para escribir registros para cada solicitud, los registros de servidor muestran que la llamada HTTP se ejecuta mediante un servicio gRPC. La transcodificación asigna la solicitud HTTP entrante a un mensaje de gRPC y, luego, convierte el mensaje de respuesta en JSON.

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET https://localhost:5001/v1/greeter/world
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'gRPC - /v1/greeter/{name}'
info: Server.GreeterService[0]
      Sending hello to world
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'gRPC - /v1/greeter/{name}'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 1.996ms 200 application/json

Anotación de métodos gRPC

Los métodos gRPC deben anotarse con una regla HTTP antes de admitir la transcodificación. La regla HTTP incluye información sobre cómo llamar al método gRPC, como el método HTTP y la ruta.

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      get: "/v1/greeter/{name}"
    };
  }
}

El ejemplo de procedimiento:

  • Define un servicio Greeter con un método SayHello. El método tiene una regla HTTP especificada con el nombre google.api.http.
  • El método es accesible con solicitudes GET y la ruta /v1/greeter/{name}.
  • El campo name del mensaje de solicitud está enlazado a un parámetro de ruta.

Hay muchas opciones disponibles para personalizar cómo un método gRPC se enlaza a una API RESTful. Para obtener más información sobre cómo anotar métodos gRPC y personalizar JSON, consulte Configuración de HTTP y JSON para la transcodificación de JSON de gRPC.

Métodos de streaming

El gRPC tradicional a través de HTTP/2 admite el streaming en todas las direcciones. La transcodificación se limita solo al streaming del servidor. No se admiten métodos de streaming de cliente ni de streaming bidireccional.

Los métodos de streaming de servidor usan JSON delimitado por líneas. Cada mensaje escrito mediante WriteAsync se serializa a JSON y va seguido de una nueva línea.

El siguiente método de streaming de servidor escribe tres mensajes:

public override async Task StreamingFromServer(ExampleRequest request,
    IServerStreamWriter<ExampleResponse> responseStream, ServerCallContext context)
{
    for (var i = 1; i <= 3; i++)
    {
        await responseStream.WriteAsync(new ExampleResponse { Text = $"Message {i}" });
        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}

El cliente recibe tres objetos JSON delimitados por líneas:

{"Text":"Message 1"}
{"Text":"Message 2"}
{"Text":"Message 3"}

Tenga en cuenta que la configuración de WriteIndentedJSON no se aplica a los métodos de streaming de servidor. La impresión con sangría agrega nuevas líneas y espacios en blanco a JSON, que no se pueden usar con JSON delimitado por líneas.

Vea o descargue un ejemplo de aplicación de transcodificación y streaming de gPRC para ASP.NET Core.

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. HTTP/2 es un buen valor predeterminado cuando una aplicación solo admite gRPC tradicional a través de HTTP/2. Sin embargo, la transcodificación 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 obtener más información sobre cómo configurar protocolos HTTP en una aplicación gRPC, consulte Negociación del protocolo gRPC de ASP.NET Core.

Transcodificación JSON de gRPC frente a gRPC-Web

Tanto la transcodificación como gRPC-Web permiten llamar a servicios gRPC desde un explorador, aunque de manera diferente:

  • gRPC-Web permite a las aplicaciones de explorador llamar a servicios gRPC desde el explorador con el cliente gRPC-Web y Protobuf. gRPC-Web requiere que la aplicación de explorador genere un cliente gRPC y tiene la ventaja de que envía mensajes de Protobuf pequeños y rápidos.
  • La transcodificación permite a las aplicaciones de explorador llamar a servicios gRPC como si fueran API RESTful con JSON. No es necesario que la aplicación de explorador genere un cliente gRPC o que disponga de información sobre gRPC.

Se puede llamar al servicio Greeter anterior mediante las API de JavaScript del explorador:

var name = nameInput.value;

fetch('/v1/greeter/' + name)
  .then((response) => response.json())
  .then((result) => {
    console.log(result.message);
    // Hello world
  });

grpc-gateway

grpc-gateway es otra tecnología para crear API JSON de RESTful desde servicios gRPC. Usa las mismas anotaciones .proto para asignar conceptos HTTP a servicios gRPC.

grpc-gateway utiliza la generación de código para crear un servidor proxy inverso. El proxy inverso traduce las llamadas RESTful a gRPC+Protobuf y envía las llamadas a través de HTTP/2 al servicio gRPC. La ventaja de este enfoque es que el servicio gRPC no conoce las API JSON de RESTful. Cualquier servidor gRPC puede usar grpc-gateway.

Mientras tanto, la transcodificación JSON de gRPC se ejecuta dentro de una aplicación de ASP.NET Core. Deserializa JSON en mensajes protobuf y, a continuación, invoca directamente el servicio gRPC. La transcodificación en ASP.NET Core ofrece ventajas a los desarrolladores de aplicaciones de .NET:

  • Menos complejo: tanto los servicios gRPC como la API JSON RESTful asignada se ejecutan fuera de una aplicación de ASP.NET Core.
  • Mejor rendimiento: la transcodificación deserializa JSON en mensajes Protobuf e invoca directamente el servicio gRPC. Hay importantes ventajas de rendimiento al hacer esto en proceso frente a realizar una nueva llamada gRPC a otro servidor.
  • Menor costo: menos servidores dan lugar a una factura de hospedaje mensual más reducida.

Para obtener información sobre la instalación y el uso de grpc-gateway, consulte el archivo LÉAME de grpc-gateway.

Recursos adicionales

gRPC es un marco de llamada a procedimiento remoto (RPC) de alto rendimiento. gRPC usa HTTP/2, streaming, Protobuf y contratos de mensaje para crear servicios en tiempo real de alto rendimiento.

Una limitación de gRPC es que no se puede usar en todas las plataformas. Los exploradores no son totalmente compatibles con HTTP/2, por lo que las API REST y JSON son la manera principal de obtener datos en aplicaciones de explorador. Incluso con las ventajas que aporta gRPC, las API REST y JSON ocupan un lugar importante en las aplicaciones modernas. La compilación de API web JSON y gRPC agrega una sobrecarga no deseada al desarrollo de aplicaciones.

En este documento se explica cómo crear API web JSON con servicios gRPC.

Información general

La transcodificación JSON de gRPC es una extensión para ASP.NET Core que crea API JSON de RESTful para servicios gRPC. Una vez configurada, la transcodificación permite que las aplicaciones llamen a servicios gRPC con conceptos conocidos de HTTP:

  • Verbos HTTP
  • Enlace de parámetros de dirección URL
  • Solicitudes y respuestas JSON

gRPC también se puede usar para llamar a servicios.

Nota

La transcodificación JSON de gRPC reemplaza la API HTTP de gRPC, una extensión experimental alternativa.

Uso

  1. Agregue una referencia de paquete a Microsoft.AspNetCore.Grpc.JsonTranscoding.
  2. Registre la transcodificación en el código de inicio del servidor agregando AddJsonTranscoding: en el archivo Program.cs, cambie builder.Services.AddGrpc(); por builder.Services.AddGrpc().AddJsonTranscoding();.
  3. Cree la estructura de directorios /google/api en el directorio del proyecto que contiene el archivo .csproj.
  4. Agregue archivos google/api/http.proto y google/api/annotations.proto al directorio /google/api.
  5. Anote los métodos gRPC en los archivos .proto con enlaces y rutas HTTP:
syntax = "proto3";

option csharp_namespace = "GrpcServiceTranscoding";
import "google/api/annotations.proto";

package greet;

// The greeting service definition.
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      get: "/v1/greeter/{name}"
    };
  }
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

El método gRPC SayHello ya se puede invocar como gRPC y como una API web de JSON:

  • Solicitud: GET /v1/greeter/world
  • Respuesta: { "message": "Hello world" }

Si el servidor está configurado para escribir registros para cada solicitud, los registros de servidor muestran que la llamada HTTP se ejecuta mediante un servicio gRPC. La transcodificación asigna la solicitud HTTP entrante a un mensaje de gRPC y, luego, convierte el mensaje de respuesta en JSON.

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET https://localhost:5001/v1/greeter/world
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'gRPC - /v1/greeter/{name}'
info: Server.GreeterService[0]
      Sending hello to world
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'gRPC - /v1/greeter/{name}'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 1.996ms 200 application/json

Anotación de métodos gRPC

Los métodos gRPC deben anotarse con una regla HTTP antes de admitir la transcodificación. La regla HTTP incluye información sobre cómo llamar al método gRPC, como el método HTTP y la ruta.

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      get: "/v1/greeter/{name}"
    };
  }
}

El ejemplo de procedimiento:

  • Define un servicio Greeter con un método SayHello. El método tiene una regla HTTP especificada con el nombre google.api.http.
  • El método es accesible con solicitudes GET y la ruta /v1/greeter/{name}.
  • El campo name del mensaje de solicitud está enlazado a un parámetro de ruta.

Hay muchas opciones disponibles para personalizar cómo un método gRPC se enlaza a una API RESTful. Para obtener más información sobre cómo anotar métodos gRPC y personalizar JSON, consulte Configuración de HTTP y JSON para la transcodificación de JSON de gRPC.

Métodos de streaming

El gRPC tradicional a través de HTTP/2 admite el streaming en todas las direcciones. La transcodificación se limita solo al streaming del servidor. No se admiten métodos de streaming de cliente ni de streaming bidireccional.

Los métodos de streaming de servidor usan JSON delimitado por líneas. Cada mensaje escrito mediante WriteAsync se serializa a JSON y va seguido de una nueva línea.

El siguiente método de streaming de servidor escribe tres mensajes:

public override async Task StreamingFromServer(ExampleRequest request,
    IServerStreamWriter<ExampleResponse> responseStream, ServerCallContext context)
{
    for (var i = 1; i <= 3; i++)
    {
        await responseStream.WriteAsync(new ExampleResponse { Text = $"Message {i}" });
        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}

El cliente recibe tres objetos JSON delimitados por líneas:

{"Text":"Message 1"}
{"Text":"Message 2"}
{"Text":"Message 3"}

Tenga en cuenta que la configuración de WriteIndentedJSON no se aplica a los métodos de streaming de servidor. La impresión con sangría agrega nuevas líneas y espacios en blanco a JSON, que no se pueden usar con JSON delimitado por líneas.

Vea o descargue un ejemplo de aplicación de transcodificación y streaming de gPRC para ASP.NET Core.

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. HTTP/2 es un buen valor predeterminado cuando una aplicación solo admite gRPC tradicional a través de HTTP/2. Sin embargo, la transcodificación 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 obtener más información sobre cómo configurar protocolos HTTP en una aplicación gRPC, consulte Negociación del protocolo gRPC de ASP.NET Core.

Transcodificación JSON de gRPC frente a gRPC-Web

Tanto la transcodificación como gRPC-Web permiten llamar a servicios gRPC desde un explorador, aunque de manera diferente:

  • gRPC-Web permite a las aplicaciones de explorador llamar a servicios gRPC desde el explorador con el cliente gRPC-Web y Protobuf. gRPC-Web requiere que la aplicación de explorador genere un cliente gRPC y tiene la ventaja de que envía mensajes de Protobuf pequeños y rápidos.
  • La transcodificación permite a las aplicaciones de explorador llamar a servicios gRPC como si fueran API RESTful con JSON. No es necesario que la aplicación de explorador genere un cliente gRPC o que disponga de información sobre gRPC.

Se puede llamar al servicio Greeter anterior mediante las API de JavaScript del explorador:

var name = nameInput.value;

fetch('/v1/greeter/' + name)
  .then((response) => response.json())
  .then((result) => {
    console.log(result.message);
    // Hello world
  });

grpc-gateway

grpc-gateway es otra tecnología para crear API JSON de RESTful desde servicios gRPC. Usa las mismas anotaciones .proto para asignar conceptos HTTP a servicios gRPC.

grpc-gateway utiliza la generación de código para crear un servidor proxy inverso. El proxy inverso traduce las llamadas RESTful a gRPC+Protobuf y envía las llamadas a través de HTTP/2 al servicio gRPC. La ventaja de este enfoque es que el servicio gRPC no conoce las API JSON de RESTful. Cualquier servidor gRPC puede usar grpc-gateway.

Mientras tanto, la transcodificación JSON de gRPC se ejecuta dentro de una aplicación de ASP.NET Core. Deserializa JSON en mensajes protobuf y, a continuación, invoca directamente el servicio gRPC. La transcodificación en ASP.NET Core ofrece ventajas a los desarrolladores de aplicaciones de .NET:

  • Menos complejo: tanto los servicios gRPC como la API JSON RESTful asignada se ejecutan fuera de una aplicación de ASP.NET Core.
  • Mejor rendimiento: la transcodificación deserializa JSON en mensajes Protobuf e invoca directamente el servicio gRPC. Hay importantes ventajas de rendimiento al hacer esto en proceso frente a realizar una nueva llamada gRPC a otro servidor.
  • Menor costo: menos servidores dan lugar a una factura de hospedaje mensual más reducida.

Para obtener información sobre la instalación y el uso de grpc-gateway, consulte el archivo LÉAME de grpc-gateway.

Recursos adicionales