Перекодирование gRPC JSON в ASP.NET Core

Автор: Джеймс Ньютон-Кинг (James Newton-King)

gRPC — это высокопроизводительная платформа удаленного вызова процедур (RPC). gRPC использует HTTP/2, потоковую передачу, Protobuf и контракты сообщений для создания высокопроизводительных служб в реальном времени.

Одним из ограничений gRPC является то, что не каждая платформа может использовать ее. Браузеры не полностью поддерживают HTTP/2, поэтому API REST и JSON остаются основными способами для передачи данных в браузерные приложения. Несмотря на преимущества, которые gRPC приносит, REST API и JSON имеют важное место в современных приложениях. Создание веб-API gRPC *иJSON добавляет нежелательные затраты на разработку приложений.

В этом документе рассматривается создание веб-API JSON с помощью служб gRPC.

Обзор

Перекодирование gRPC JSON — это расширение для ASP.NET Core, которое создает REST API JSON для служб gRPC. Настроенное перекодирование позволяет приложениям вызывать службы gRPC, используя следующие привычные понятия HTTP:

  • HTTP-команды
  • привязку параметра URL-адреса;
  • запросы и ответы в формате JSON.

gRPC по-прежнему можно использовать для вызова служб.

Примечание.

Перекодирование gRPC JSON заменяет собой альтернативное экспериментальное расширение API HTTP gRPC.

Использование

  1. Добавьте ссылку на пакет для Microsoft.AspNetCore.Grpc.JsonTranscoding.

  2. Зарегистрируйте перекодирование в коде запуска сервера, добавив AddJsonTranscoding: в Program.cs файле изменится builder.Services.AddGrpc(); на builder.Services.AddGrpc().AddJsonTranscoding();.

  3. Добавьте <IncludeHttpRuleProtos>true</IncludeHttpRuleProtos> в группу свойств в файле проекта (.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. Заметьте методы gRPC в .proto файлах с привязками и маршрутами 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;
    }
    

Теперь метод SayHello gRPC можно вызывать как gRPC и веб-API JSON:

  • Запрос: GET /v1/greeter/world
  • Ответ: { "message": "Hello world" }

Если сервер настроен на запись журналов для каждого запроса, журналы сервера показывают, что служба gRPC выполняет http-вызов. Перекодирование сопоставляет входящий HTTP-запрос с сообщением gRPC и преобразует ответное сообщение в 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

Аннотировать методы gRPC

Методы gRPC должны быть аннотированы с помощью правила HTTP, прежде чем они поддерживают перекодирование. Правило HTTP содержит сведения о том, как вызвать метод gRPC, например метод HTTP и маршрут.

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

Пример процедуры:

  • Определяет Greeter службу с методом SayHello . Метод имеет правило HTTP, указанное с помощью имени google.api.http.
  • Метод доступен с запросами GET и маршрутом /v1/greeter/{name} .
  • name Поле сообщения запроса привязано к параметру маршрута.

Многие варианты доступны для настройки привязки метода gRPC к RESTAPI с ful. Дополнительные сведения о аннотации методов gRPC и настройке JSON см. в разделе "Настройка HTTP и JSON" для транскодирования gRPC JSON.

Методы потоковой передачи

Традиционный API gRPC по HTTP/2 поддерживает потоковую передачу во всех направлениях. Перекодирование предназначено только для серверной потоковой передачи. Методы клиентской и двунаправленной потоковой передачи не поддерживаются.

Методы серверной потоковой передачи используют JSON с разделителями строк. Каждое сообщение, записанное с помощью WriteAsync, сериализуется в JSON, за которым следует новая строка.

Следующий метод серверной потоковой передачи записывает три сообщения:

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

Клиент получает три объекта JSON с разделителями строк:

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

Обратите внимание, что параметр JSON WriteIndented не применяется к методам серверной потоковой передачи. Автоматическое форматирование добавляет новые строки и пробел в JSON, которые нельзя использовать в JSON с разделителями строк.

Просмотр или скачивание примера приложения ASP.NET Core gPRC для перекодирования и потоковой передачи.

Протокол HTTP

Шаблон службы ASP.NET Core gRPC, включенный в пакет SDK для .NET, создает приложение, настроенное только для HTTP/2. HTTP/2 является хорошим по умолчанию, если приложение поддерживает только традиционные gRPC по протоколу HTTP/2. Однако перекодирование работает как с HTTP/1.1, так и с HTTP/2. Некоторые платформы, например UWP или Unity, не могут использовать HTTP/2. Чтобы обеспечить поддержку всех клиентских приложений, настройте сервер для включения HTTP/1.1 и HTTP/2.

Обновите протокол умолчанию в файле appsettings.json:

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

Как вариант, вы можете настроить конечные точки Kestrel в коде запуска.

Чтобы включить HTTP/1.1 и HTTP/2 на одном порте, требуется TLS для согласования протокола. Дополнительные сведения о настройке протоколов HTTP в приложении gRPC см. в разделе Согласование протокола gRPC в ASP.NET Core.

Сравнение перекодирования JSON с gRPC-Web

Как перекодирование, так и gRPC-Web позволяют вызывать службы gRPC из браузера. Однако способы, которыми они это делают, отличаются.

  • gRPC-Web позволяет браузерным приложениям вызывать службы gRPC из браузера с помощью клиента gRPC-Web и Protobuf. gRPC-Web требует, чтобы приложение браузера создало клиент gRPC и имеет преимущество отправки небольших, быстрых сообщений Protobuf.
  • Перекодирование позволяет браузерным приложениям вызывать службы gRPC, как обычные REST API с поддержкой формата JSON. Браузерному приложению не нужно создавать клиент gRPC и не нужно ничего знать о gRPC.

Предыдущую службу Greeter можно вызывать с помощью API JavaScript браузера:

var name = nameInput.value;

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

grpc-gateway

grpc-gateway — еще одна технология создания REST API JSON на основе служб gRPC. В нем используются те же .proto заметки для сопоставления концепций HTTP с службами gRPC.

grpc-gateway использует генерирование кода для создания обратного прокси-сервера. Обратный прокси-сервер преобразует вызовы RESTful в формат gRPC+Protobuf и отправляет вызовы по протоколу HTTP/2 в службу gRPC. Преимущество этого подхода заключается в том, что службе gRPC не нужна информация об REST API JSON. Любой сервер gRPC может использовать grpc-gateway.

Между тем перекодирование gRPC JSON выполняется в приложении ASP.NET Core. Оно десериализует содержимое JSON в сообщения формата Protobuf, а затем напрямую вызывает службу gRPC. Перекодирование в ASP.NET Core предоставляет следующие преимущества для разработчиков приложений .NET:

  • Снижение сложности: службы gRPC и сопоставленные с ними REST API JSON выполняются из одного приложения ASP.NET Core.
  • Повышение производительности: перекодирование десериализует JSON в сообщения Protobuf и напрямую вызывает службу gRPC. Существует значительное преимущество, связанное с производительностью, при выполнении этого внутрипроцессного вызова, а не при вызове gRPC к другому серверу.
  • Снижение стоимости: меньшее количество серверов приводит к уменьшению ежемесячного счета за размещение.

Сведения об установке и использовании grpc-gateway см. в файле сведений для grpc-gateway.

Дополнительные ресурсы

gRPC — это высокопроизводительная платформа удаленного вызова процедур (RPC). gRPC использует HTTP/2, потоковую передачу, Protobuf и контракты сообщений для создания высокопроизводительных служб в реальном времени.

Одним из ограничений gRPC является то, что не каждая платформа может использовать ее. Браузеры не полностью поддерживают HTTP/2, поэтому API REST и JSON остаются основными способами для передачи данных в браузерные приложения. Несмотря на преимущества, которые gRPC приносит, REST API и JSON имеют важное место в современных приложениях. Создание веб-API gRPC *иJSON добавляет нежелательные затраты на разработку приложений.

В этом документе рассматривается создание веб-API JSON с помощью служб gRPC.

Обзор

Перекодирование gRPC JSON — это расширение для ASP.NET Core, которое создает REST API JSON для служб gRPC. Настроенное перекодирование позволяет приложениям вызывать службы gRPC, используя следующие привычные понятия HTTP:

  • HTTP-команды
  • привязку параметра URL-адреса;
  • запросы и ответы в формате JSON.

gRPC по-прежнему можно использовать для вызова служб.

Примечание.

Перекодирование gRPC JSON заменяет собой альтернативное экспериментальное расширение API HTTP gRPC.

Использование

  1. Добавьте ссылку на пакет для Microsoft.AspNetCore.Grpc.JsonTranscoding.
  2. Зарегистрируйте перекодирование в коде запуска сервера, добавив AddJsonTranscoding: в Program.cs файле изменится builder.Services.AddGrpc(); на builder.Services.AddGrpc().AddJsonTranscoding();.
  3. Создайте структуру /google/api каталогов в каталоге проекта, который содержит .csproj файл.
  4. Добавьте google/api/http.proto и google/api/annotations.proto файлы в /google/api каталог.
  5. Заметьте методы gRPC в .proto файлах с привязками и маршрутами 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;
}

Теперь метод SayHello gRPC можно вызывать как gRPC и веб-API JSON:

  • Запрос: GET /v1/greeter/world
  • Ответ: { "message": "Hello world" }

Если сервер настроен на запись журналов для каждого запроса, журналы сервера показывают, что служба gRPC выполняет http-вызов. Перекодирование сопоставляет входящий HTTP-запрос с сообщением gRPC и преобразует ответное сообщение в 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

Аннотировать методы gRPC

Методы gRPC должны быть аннотированы с помощью правила HTTP, прежде чем они поддерживают перекодирование. Правило HTTP содержит сведения о том, как вызвать метод gRPC, например метод HTTP и маршрут.

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

Пример процедуры:

  • Определяет Greeter службу с методом SayHello . Метод имеет правило HTTP, указанное с помощью имени google.api.http.
  • Метод доступен с запросами GET и маршрутом /v1/greeter/{name} .
  • name Поле сообщения запроса привязано к параметру маршрута.

Многие варианты доступны для настройки привязки метода gRPC к RESTAPI с ful. Дополнительные сведения о аннотации методов gRPC и настройке JSON см. в разделе "Настройка HTTP и JSON" для транскодирования gRPC JSON.

Методы потоковой передачи

Традиционный API gRPC по HTTP/2 поддерживает потоковую передачу во всех направлениях. Перекодирование предназначено только для серверной потоковой передачи. Методы клиентской и двунаправленной потоковой передачи не поддерживаются.

Методы серверной потоковой передачи используют JSON с разделителями строк. Каждое сообщение, записанное с помощью WriteAsync, сериализуется в JSON, за которым следует новая строка.

Следующий метод серверной потоковой передачи записывает три сообщения:

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

Клиент получает три объекта JSON с разделителями строк:

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

Обратите внимание, что параметр JSON WriteIndented не применяется к методам серверной потоковой передачи. Автоматическое форматирование добавляет новые строки и пробел в JSON, которые нельзя использовать в JSON с разделителями строк.

Просмотр или скачивание примера приложения ASP.NET Core gPRC для перекодирования и потоковой передачи.

Протокол HTTP

Шаблон службы ASP.NET Core gRPC, включенный в пакет SDK для .NET, создает приложение, настроенное только для HTTP/2. HTTP/2 является хорошим по умолчанию, если приложение поддерживает только традиционные gRPC по протоколу HTTP/2. Однако перекодирование работает как с HTTP/1.1, так и с HTTP/2. Некоторые платформы, например UWP или Unity, не могут использовать HTTP/2. Чтобы обеспечить поддержку всех клиентских приложений, настройте сервер для включения HTTP/1.1 и HTTP/2.

Обновите протокол умолчанию в файле appsettings.json:

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

Как вариант, вы можете настроить конечные точки Kestrel в коде запуска.

Чтобы включить HTTP/1.1 и HTTP/2 на одном порте, требуется TLS для согласования протокола. Дополнительные сведения о настройке протоколов HTTP в приложении gRPC см. в разделе Согласование протокола gRPC в ASP.NET Core.

Сравнение перекодирования JSON с gRPC-Web

Как перекодирование, так и gRPC-Web позволяют вызывать службы gRPC из браузера. Однако способы, которыми они это делают, отличаются.

  • gRPC-Web позволяет браузерным приложениям вызывать службы gRPC из браузера с помощью клиента gRPC-Web и Protobuf. gRPC-Web требует, чтобы приложение браузера создало клиент gRPC и имеет преимущество отправки небольших, быстрых сообщений Protobuf.
  • Перекодирование позволяет браузерным приложениям вызывать службы gRPC, как обычные REST API с поддержкой формата JSON. Браузерному приложению не нужно создавать клиент gRPC и не нужно ничего знать о gRPC.

Предыдущую службу Greeter можно вызывать с помощью API JavaScript браузера:

var name = nameInput.value;

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

grpc-gateway

grpc-gateway — еще одна технология создания REST API JSON на основе служб gRPC. В нем используются те же .proto заметки для сопоставления концепций HTTP с службами gRPC.

grpc-gateway использует генерирование кода для создания обратного прокси-сервера. Обратный прокси-сервер преобразует вызовы RESTful в формат gRPC+Protobuf и отправляет вызовы по протоколу HTTP/2 в службу gRPC. Преимущество этого подхода заключается в том, что службе gRPC не нужна информация об REST API JSON. Любой сервер gRPC может использовать grpc-gateway.

Между тем перекодирование gRPC JSON выполняется в приложении ASP.NET Core. Оно десериализует содержимое JSON в сообщения формата Protobuf, а затем напрямую вызывает службу gRPC. Перекодирование в ASP.NET Core предоставляет следующие преимущества для разработчиков приложений .NET:

  • Снижение сложности: службы gRPC и сопоставленные с ними REST API JSON выполняются из одного приложения ASP.NET Core.
  • Повышение производительности: перекодирование десериализует JSON в сообщения Protobuf и напрямую вызывает службу gRPC. Существует значительное преимущество, связанное с производительностью, при выполнении этого внутрипроцессного вызова, а не при вызове gRPC к другому серверу.
  • Снижение стоимости: меньшее количество серверов приводит к уменьшению ежемесячного счета за размещение.

Сведения об установке и использовании grpc-gateway см. в файле сведений для grpc-gateway.

Дополнительные ресурсы