gRPC-Web в приложениях ASP.NET Core gRPC

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

Узнайте, как настроить существующую службу ASP.NET Core gRPC для вызовов из приложений браузера с использованием протокола gRPC-Web. gRPC-Web позволяет приложениям JavaScript и Blazor на основе браузера вызывать службы gRPC. Вызвать службу HTTP/2 gRPC из приложения на основе браузера нельзя. Службы gRPC, размещенные в ASP.NET Core, можно настроить на поддержку gRPC-Web вместе с HTTP/2 gRPC.

См. раздел Добавление служб gRPC в приложение ASP.NET Core.

Инструкции по созданию проекта gRPC см. в статье Создание клиента и сервера .NET Core gRPC в ASP.NET Core.

Сравнение ASP.NET Core gRPC-Web с Envoy

Существует два способа добавления gRPC-Web в приложение ASP.NET Core.

  • Поддержка gRPC-Web вместе с gRPC HTTP/2 в ASP.NET Core. Этот параметр использует ПО промежуточного слоя, предоставленное пакетом Grpc.AspNetCore.Web.
  • Используйте поддержку gRPC-Web в прокси-сервере Envoy, чтобы транслировать gRPC-Web в gRPC HTTP/2. Затем переведенный вызов перенаправляется в приложение ASP.NET Core.

Есть свои плюсы и минусы этого подхода. Если среда приложения уже использует Envoy в качестве прокси-сервера, имеет смысл использовать Envoy и для предоставления поддержки gRPC-Web. Если требуется простое решение для gRPC-Web, для которого требуется только ASP.NET Core, используйте Grpc.AspNetCore.Web.

Настройка gRPC-Web в ASP.NET Core

Службы gRPC, размещенные в ASP.NET Core, можно настроить на поддержку gRPC-Web вместе с HTTP/2 gRPC. gRPC-Web не требует вносить изменения в службы. Единственное изменение заключается в настройке ПО промежуточного слоя Program.cs.

Чтобы включить gRPC-Web со службой gRPC ASP.NET Core, выполните следующие действия.

  • добавьте ссылку на пакет Grpc.AspNetCore.Web;
  • Настройте приложение для использования gRPC-Web, добавив UseGrpcWeb и EnableGrpcWeb в 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();

Предыдущий код:

  • Добавляет ПО промежуточного слоя gRPC-Web (UseGrpcWeb) после маршрутизации и перед конечными точками.
  • Указывает, что метод endpoints.MapGrpcService<GreeterService>() поддерживает gRPC-Web с EnableGrpcWeb.

Можно также настроить ПО промежуточного слоя gRPC-Web, чтобы все службы поддерживали gRPC-Web по умолчанию и не нужно было использовать EnableGrpcWeb. Укажите new GrpcWebOptions { DefaultEnabled = true } при добавлении ПО промежуточного слоя.

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

Примечание.

Существует известная ошибка, приводящая к сбою gRPC-Web при размещении с помощью HTTP.sys в .NET Core 3.x.

Временное решение для запуска gRPC-Web на HTTP.sys доступно в разделе Экспериментальное использование gRPC-Web и UseHttpSys() (grpc/grpc-dotnet № 853).

gRPC-Web и CORS

Система безопасности браузера предотвращает запросы веб-страницы к другому домену, отличному от того, который обслуживает веб-страницу. Это ограничение применяется к вызовам gRPC-Web с приложениями браузера. Например, приложение браузера, обслуживаемое https://www.contoso.com, блокирует вызов служб gRPC-Web, размещенных на https://services.contoso.com. Можно использовать общий доступ к ресурсам независимо от источника (CORS), чтобы ослабить это ограничение.

Чтобы разрешить приложению браузера вызывать gRPC-Web независимо от источника, настройте CORS в ASP.NET Core. Используйте встроенную поддержку CORS и предоставьте заголовки, относящиеся к gRPC, с помощью 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();

Предыдущий код:

  • Вызывает AddCors для добавления служб CORS и настройки политики CORS, которая предоставляет заголовки, относящиеся к gRPC.
  • Вызывает UseCors для добавления ПО промежуточного слоя CORS после настройки маршрутизации и перед настройкой конечных точек.
  • Указывает, что метод endpoints.MapGrpcService<GreeterService>() поддерживает CORS с RequireCors.

gRPC-Web и потоковая передача

Традиционный протокол gRPC на основе HTTP/2 поддерживает клиентскую, серверную и двунаправленную потоковую передачу. gRPC-Web имеет ограниченную поддержку потоковой передачи:

  • Клиенты браузера с gRPC-Web не поддерживают вызов методов потоковой передачи клиента и двунаправленной потоковой передачи.
  • Клиенты .NET с gRPC-Web не поддерживают вызов на клиенте методов потоковой передачи и двунаправленной потоковой передачи по протоколу HTTP/1.1.
  • Службы gRPC в ASP.NET Core, размещенные в Службе приложений Azure и IIS, не поддерживают двунаправленную потоковую передачу.

При использовании gRPC-Web мы рекомендуем применять только унарные методы и методы серверной потоковой передачи.

Протокол HTTP

Шаблон службы ASP.NET Core gRPC, включенный в пакет SDK для .NET, создает приложение, настроенное только для HTTP/2. Это хорошая настройка по умолчанию, если приложение поддерживает только традиционный протокол gRPC на основе HTTP/2. Однако gRPC-Web работает как с 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 для согласования протокола. Дополнительные сведения см. в разделе Согласование протокола ASP.NET Core.

Вызов gRPC-Web из браузера

Приложения браузера могут использовать gRPC-Web для вызова служб gRPC. При вызове служб gRPC с помощью gRPC-Web из браузера существует ряд требований и ограничений.

  • Сервер должен содержать конфигурацию для поддержки gRPC-Web.
  • Потоковая передача клиента и вызовы двунаправленной потоковой передачи не поддерживаются. Потоковая передача сервера поддерживается.
  • Для вызова служб gRPC в другом домене требуется настроить CORS на сервере.

Клиент gRPC-Web JavaScript

Существуют клиенты gRPC-Web для JavaScript. Инструкции по использованию gRPC-Web из JavaScript см. в статье, посвященной написанию кода клиента JavaScript с gRPC-Web.

Настройка gRPC-Web с помощью клиента .NET gRPC

Клиент .NET gRPC можно настроить для выполнения вызовов gRPC-Web. Это полезно для приложений Blazor WebAssembly, которые размещаются в браузере и имеют те же ограничения HTTP, что и код JavaScript. Вызов gRPC-Web с помощью клиента .NET выполняется так же, как и для HTTP/2 gRPC. Единственным изменением является то, как создается канал.

Чтобы использовать gRPC-Web:

  • добавьте ссылку на пакет Grpc.Net.Client.Web;
  • убедитесь, что используется ссылка на пакет Grpc.Net.Client версии 2.29.0 или более поздней;
  • Настройте канал на использование 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" });

Предыдущий код:

  • Настраивает канал для использования gRPC-Web.
  • Создает клиент и выполняет вызов с помощью канала.

GrpcWebHandler имеет следующие параметры конфигурации.

  • InnerHandler: базовый HttpMessageHandler объект, который делает HTTP-запрос gRPC, например HttpClientHandler.
  • GrpcWebMode: тип перечисления, указывающий, является application/grpc-web ли HTTP-запрос Content-Type gRPC или application/grpc-web-text.
    • GrpcWebMode.GrpcWeb настраивает отправку содержимого без кодирования. Значение по умолчанию.
    • GrpcWebMode.GrpcWebText настраивает содержимое в кодировке Base64. Требуется для вызовов потоковой передачи сервера в браузерах.
  • HttpVersion: протокол Version HTTP, используемый для установки HttpRequestMessage.Version в базовом HTTP-запросе gRPC. gRPC-Web не требует определенной версии и не переопределяет значение по умолчанию, если не указано иное.

Важно!

Созданные клиенты gRPC имеют синхронные и асинхронные методы для вызова унарных методов. Например, SayHello является синхронным, а SayHelloAsync — асинхронным. Асинхронные методы всегда требуются в Blazor WebAssembly. Вызов синхронного метода в приложении Blazor WebAssembly приведет к тому, что приложение перестанет отвечать на запросы.

Использование фабрики клиента gRPC с gRPC-Web

Создайте клиент .NET, совместимый с gRPC-Web, с помощью фабрики клиентов gRPC:

  • Добавьте ссылки на пакеты в файл проекта для следующих пакетов:
  • Зарегистрируйте клиент gRPC с внедрением зависимостей (DI) с помощью универсального метода расширения AddGrpcClient. В приложении Blazor WebAssembly службы регистрируются с внедрением зависимостей в Program.cs.
  • Настройте GrpcWebHandler с помощью метода расширения ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Дополнительные сведения см. в статье Интеграция фабрики клиента gRPC в .NET.

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

Узнайте, как настроить существующую службу ASP.NET Core gRPC для вызовов из приложений браузера с использованием протокола gRPC-Web. gRPC-Web позволяет приложениям JavaScript и Blazor на основе браузера вызывать службы gRPC. Вызвать службу HTTP/2 gRPC из приложения на основе браузера нельзя. Службы gRPC, размещенные в ASP.NET Core, можно настроить на поддержку gRPC-Web вместе с HTTP/2 gRPC.

См. раздел Добавление служб gRPC в приложение ASP.NET Core.

Инструкции по созданию проекта gRPC см. в статье Создание клиента и сервера .NET Core gRPC в ASP.NET Core.

Сравнение ASP.NET Core gRPC-Web с Envoy

Существует два способа добавления gRPC-Web в приложение ASP.NET Core.

  • Поддержка gRPC-Web вместе с gRPC HTTP/2 в ASP.NET Core. Этот параметр использует ПО промежуточного слоя, предоставленное пакетом Grpc.AspNetCore.Web.
  • Используйте поддержку gRPC-Web в прокси-сервере Envoy, чтобы транслировать gRPC-Web в gRPC HTTP/2. Затем переведенный вызов перенаправляется в приложение ASP.NET Core.

Есть свои плюсы и минусы этого подхода. Если среда приложения уже использует Envoy в качестве прокси-сервера, имеет смысл использовать Envoy и для предоставления поддержки gRPC-Web. Если требуется простое решение для gRPC-Web, для которого требуется только ASP.NET Core, используйте Grpc.AspNetCore.Web.

Настройка gRPC-Web в ASP.NET Core

Службы gRPC, размещенные в ASP.NET Core, можно настроить на поддержку gRPC-Web вместе с HTTP/2 gRPC. gRPC-Web не требует вносить изменения в службы. Единственное изменение заключается в настройке middelware в Program.cs.

Чтобы включить gRPC-Web со службой gRPC ASP.NET Core, выполните следующие действия.

  • добавьте ссылку на пакет Grpc.AspNetCore.Web;
  • Настройте приложение для использования gRPC-Web, добавив UseGrpcWeb и EnableGrpcWeb в 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();

Предыдущий код:

  • Добавляет ПО промежуточного слоя gRPC-Web (UseGrpcWeb) после маршрутизации и перед конечными точками.
  • Указывает, что метод endpoints.MapGrpcService<GreeterService>() поддерживает gRPC-Web с EnableGrpcWeb.

Можно также настроить ПО промежуточного слоя gRPC-Web, чтобы все службы поддерживали gRPC-Web по умолчанию и не нужно было использовать EnableGrpcWeb. Укажите new GrpcWebOptions { DefaultEnabled = true } при добавлении ПО промежуточного слоя.

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

Примечание.

Существует известная ошибка, приводящая к сбою gRPC-Web при размещении с помощью HTTP.sys в .NET Core 3.x.

Временное решение для запуска gRPC-Web на HTTP.sys доступно в разделе Экспериментальное использование gRPC-Web и UseHttpSys() (grpc/grpc-dotnet № 853).

gRPC-Web и CORS

Система безопасности браузера предотвращает запросы веб-страницы к другому домену, отличному от того, который обслуживает веб-страницу. Это ограничение применяется к вызовам gRPC-Web с приложениями браузера. Например, приложение браузера, обслуживаемое https://www.contoso.com, блокирует вызов служб gRPC-Web, размещенных на https://services.contoso.com. Можно использовать общий доступ к ресурсам независимо от источника (CORS), чтобы ослабить это ограничение.

Чтобы разрешить приложению браузера вызывать gRPC-Web независимо от источника, настройте CORS в ASP.NET Core. Используйте встроенную поддержку CORS и предоставьте заголовки, относящиеся к gRPC, с помощью 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();

Предыдущий код:

  • Вызывает AddCors для добавления служб CORS и настройки политики CORS, которая предоставляет заголовки, относящиеся к gRPC.
  • Вызывает UseCors для добавления ПО промежуточного слоя CORS после настройки маршрутизации и перед настройкой конечных точек.
  • Указывает, что метод endpoints.MapGrpcService<GreeterService>() поддерживает CORS с RequireCors.

gRPC-Web и потоковая передача

Традиционный протокол gRPC на основе HTTP/2 поддерживает клиентскую, серверную и двунаправленную потоковую передачу. gRPC-Web имеет ограниченную поддержку потоковой передачи:

  • Клиенты браузера с gRPC-Web не поддерживают вызов методов потоковой передачи клиента и двунаправленной потоковой передачи.
  • Клиенты .NET с gRPC-Web не поддерживают вызов на клиенте методов потоковой передачи и двунаправленной потоковой передачи по протоколу HTTP/1.1.
  • Службы gRPC в ASP.NET Core, размещенные в Службе приложений Azure и IIS, не поддерживают двунаправленную потоковую передачу.

При использовании gRPC-Web мы рекомендуем применять только унарные методы и методы серверной потоковой передачи.

Протокол HTTP

Шаблон службы ASP.NET Core gRPC, включенный в пакет SDK для .NET, создает приложение, настроенное только для HTTP/2. Это хорошая настройка по умолчанию, если приложение поддерживает только традиционный протокол gRPC на основе HTTP/2. Однако gRPC-Web работает как с 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 для согласования протокола. Дополнительные сведения см. в разделе Согласование протокола ASP.NET Core.

Вызов gRPC-Web из браузера

Приложения браузера могут использовать gRPC-Web для вызова служб gRPC. При вызове служб gRPC с помощью gRPC-Web из браузера существует ряд требований и ограничений.

  • Сервер должен содержать конфигурацию для поддержки gRPC-Web.
  • Потоковая передача клиента и вызовы двунаправленной потоковой передачи не поддерживаются. Потоковая передача сервера поддерживается.
  • Для вызова служб gRPC в другом домене требуется настроить CORS на сервере.

Клиент gRPC-Web JavaScript

Существуют клиенты gRPC-Web для JavaScript. Инструкции по использованию gRPC-Web из JavaScript см. в статье, посвященной написанию кода клиента JavaScript с gRPC-Web.

Настройка gRPC-Web с помощью клиента .NET gRPC

Клиент .NET gRPC можно настроить для выполнения вызовов gRPC-Web. Это полезно для приложений Blazor WebAssembly, которые размещаются в браузере и имеют те же ограничения HTTP, что и код JavaScript. Вызов gRPC-Web с помощью клиента .NET выполняется так же, как и для HTTP/2 gRPC. Единственным изменением является то, как создается канал.

Чтобы использовать gRPC-Web:

  • добавьте ссылку на пакет Grpc.Net.Client.Web;
  • убедитесь, что используется ссылка на пакет Grpc.Net.Client версии 2.29.0 или более поздней;
  • Настройте канал на использование 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" });

Предыдущий код:

  • Настраивает канал для использования gRPC-Web.
  • Создает клиент и выполняет вызов с помощью канала.

GrpcWebHandler имеет следующие параметры конфигурации.

  • InnerHandler: базовый HttpMessageHandler объект, который делает HTTP-запрос gRPC, например HttpClientHandler.
  • GrpcWebMode: тип перечисления, указывающий, является application/grpc-web ли HTTP-запрос Content-Type gRPC или application/grpc-web-text.
    • GrpcWebMode.GrpcWeb настраивает отправку содержимого без кодирования. Значение по умолчанию.
    • GrpcWebMode.GrpcWebText настраивает содержимое в кодировке Base64. Требуется для вызовов потоковой передачи сервера в браузерах.
  • HttpVersion: протокол Version HTTP, используемый для установки HttpRequestMessage.Version в базовом HTTP-запросе gRPC. gRPC-Web не требует определенной версии и не переопределяет значение по умолчанию, если не указано иное.

Важно!

Созданные клиенты gRPC имеют синхронные и асинхронные методы для вызова унарных методов. Например, SayHello является синхронным, а SayHelloAsync — асинхронным. Асинхронные методы всегда требуются в Blazor WebAssembly. Вызов синхронного метода в приложении Blazor WebAssembly приведет к тому, что приложение перестанет отвечать на запросы.

Использование фабрики клиента gRPC с gRPC-Web

Создайте клиент .NET, совместимый с gRPC-Web, с помощью фабрики клиентов gRPC:

  • Добавьте ссылки на пакеты в файл проекта для следующих пакетов:
  • Зарегистрируйте клиент gRPC с внедрением зависимостей (DI) с помощью универсального метода расширения AddGrpcClient. В приложении Blazor WebAssembly службы регистрируются с внедрением зависимостей в Program.cs.
  • Настройте GrpcWebHandler с помощью метода расширения ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Дополнительные сведения см. в статье Интеграция фабрики клиента gRPC в .NET.

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

Узнайте, как настроить существующую службу ASP.NET Core gRPC для вызовов из приложений браузера с использованием протокола gRPC-Web. gRPC-Web позволяет приложениям JavaScript и Blazor на основе браузера вызывать службы gRPC. Вызвать службу HTTP/2 gRPC из приложения на основе браузера нельзя. Службы gRPC, размещенные в ASP.NET Core, можно настроить на поддержку gRPC-Web вместе с HTTP/2 gRPC.

См. раздел Добавление служб gRPC в приложение ASP.NET Core.

Инструкции по созданию проекта gRPC см. в статье Создание клиента и сервера .NET Core gRPC в ASP.NET Core.

Сравнение ASP.NET Core gRPC-Web с Envoy

Существует два способа добавления gRPC-Web в приложение ASP.NET Core.

  • Поддержка gRPC-Web вместе с gRPC HTTP/2 в ASP.NET Core. Этот параметр использует ПО промежуточного слоя, предоставленное пакетом Grpc.AspNetCore.Web.
  • Используйте поддержку gRPC-Web в прокси-сервере Envoy, чтобы транслировать gRPC-Web в gRPC HTTP/2. Затем переведенный вызов перенаправляется в приложение ASP.NET Core.

Есть свои плюсы и минусы этого подхода. Если среда приложения уже использует Envoy в качестве прокси-сервера, имеет смысл использовать Envoy и для предоставления поддержки gRPC-Web. Если требуется простое решение для gRPC-Web, для которого требуется только ASP.NET Core, используйте Grpc.AspNetCore.Web.

Настройка gRPC-Web в ASP.NET Core

Службы gRPC, размещенные в ASP.NET Core, можно настроить на поддержку gRPC-Web вместе с HTTP/2 gRPC. gRPC-Web не требует вносить изменения в службы. Единственного изменения потребует конфигурация запуска.

Чтобы включить gRPC-Web со службой gRPC ASP.NET Core, выполните следующие действия.

  • добавьте ссылку на пакет Grpc.AspNetCore.Web;
  • Настройте приложение для использования gRPC-Web, добавив UseGrpcWeb и EnableGrpcWeb в 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();
    });
}

Предыдущий код:

  • Добавляет ПО промежуточного слоя gRPC-Web (UseGrpcWeb) после маршрутизации и перед конечными точками.
  • Указывает, что метод endpoints.MapGrpcService<GreeterService>() поддерживает gRPC-Web с EnableGrpcWeb.

Можно также настроить ПО промежуточного слоя gRPC-Web, чтобы все службы поддерживали gRPC-Web по умолчанию и не нужно было использовать EnableGrpcWeb. Укажите new GrpcWebOptions { DefaultEnabled = true } при добавлении ПО промежуточного слоя.

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

Примечание.

Существует известная ошибка, приводящая к сбою gRPC-Web при размещении с помощью HTTP.sys в .NET Core 3.x.

Временное решение для запуска gRPC-Web на HTTP.sys доступно в разделе Экспериментальное использование gRPC-Web и UseHttpSys() (grpc/grpc-dotnet № 853).

gRPC-Web и CORS

Система безопасности браузера предотвращает запросы веб-страницы к другому домену, отличному от того, который обслуживает веб-страницу. Это ограничение применяется к вызовам gRPC-Web с приложениями браузера. Например, приложение браузера, обслуживаемое https://www.contoso.com, блокирует вызов служб gRPC-Web, размещенных на https://services.contoso.com. Можно использовать общий доступ к ресурсам независимо от источника (CORS), чтобы ослабить это ограничение.

Чтобы разрешить приложению браузера вызывать gRPC-Web независимо от источника, настройте CORS в ASP.NET Core. Используйте встроенную поддержку CORS и предоставьте заголовки, относящиеся к gRPC, с помощью 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");
    });
}

Предыдущий код:

  • Вызывает AddCors для добавления служб CORS и настройки политики CORS, которая предоставляет заголовки, относящиеся к gRPC.
  • Вызывает UseCors для добавления ПО промежуточного слоя CORS после настройки маршрутизации и перед настройкой конечных точек.
  • Указывает, что метод endpoints.MapGrpcService<GreeterService>() поддерживает CORS с RequireCors.

gRPC-Web и потоковая передача

Традиционный протокол gRPC на основе HTTP/2 поддерживает клиентскую, серверную и двунаправленную потоковую передачу. gRPC-Web имеет ограниченную поддержку потоковой передачи:

  • Клиенты браузера с gRPC-Web не поддерживают вызов методов потоковой передачи клиента и двунаправленной потоковой передачи.
  • Клиенты .NET с gRPC-Web не поддерживают вызов на клиенте методов потоковой передачи и двунаправленной потоковой передачи по протоколу HTTP/1.1.
  • Службы gRPC в ASP.NET Core, размещенные в Службе приложений Azure и IIS, не поддерживают двунаправленную потоковую передачу.

При использовании gRPC-Web мы рекомендуем применять только унарные методы и методы серверной потоковой передачи.

Протокол HTTP

Шаблон службы ASP.NET Core gRPC, включенный в пакет SDK для .NET, создает приложение, настроенное только для HTTP/2. Это хорошая настройка по умолчанию, если приложение поддерживает только традиционный протокол gRPC на основе HTTP/2. Однако gRPC-Web работает как с 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 для согласования протокола. Дополнительные сведения см. в разделе Согласование протокола ASP.NET Core.

Вызов gRPC-Web из браузера

Приложения браузера могут использовать gRPC-Web для вызова служб gRPC. При вызове служб gRPC с помощью gRPC-Web из браузера существует ряд требований и ограничений.

  • Сервер должен содержать конфигурацию для поддержки gRPC-Web.
  • Потоковая передача клиента и вызовы двунаправленной потоковой передачи не поддерживаются. Потоковая передача сервера поддерживается.
  • Для вызова служб gRPC в другом домене требуется настроить CORS на сервере.

Клиент gRPC-Web JavaScript

Существуют клиенты gRPC-Web для JavaScript. Инструкции по использованию gRPC-Web из JavaScript см. в статье, посвященной написанию кода клиента JavaScript с gRPC-Web.

Настройка gRPC-Web с помощью клиента .NET gRPC

Клиент .NET gRPC можно настроить для выполнения вызовов gRPC-Web. Это полезно для приложений Blazor WebAssembly, которые размещаются в браузере и имеют те же ограничения HTTP, что и код JavaScript. Вызов gRPC-Web с помощью клиента .NET выполняется так же, как и для HTTP/2 gRPC. Единственным изменением является то, как создается канал.

Чтобы использовать gRPC-Web:

  • добавьте ссылку на пакет Grpc.Net.Client.Web;
  • убедитесь, что используется ссылка на пакет Grpc.Net.Client версии 2.29.0 или более поздней;
  • Настройте канал на использование 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" });

Предыдущий код:

  • Настраивает канал для использования gRPC-Web.
  • Создает клиент и выполняет вызов с помощью канала.

GrpcWebHandler имеет следующие параметры конфигурации.

  • InnerHandler: базовый HttpMessageHandler объект, который делает HTTP-запрос gRPC, например HttpClientHandler.
  • GrpcWebMode: тип перечисления, указывающий, является application/grpc-web ли HTTP-запрос Content-Type gRPC или application/grpc-web-text.
    • GrpcWebMode.GrpcWeb настраивает отправку содержимого без кодирования. Значение по умолчанию.
    • GrpcWebMode.GrpcWebText настраивает содержимое в кодировке Base64. Требуется для вызовов потоковой передачи сервера в браузерах.
  • HttpVersion: протокол Version HTTP, используемый для установки HttpRequestMessage.Version в базовом HTTP-запросе gRPC. gRPC-Web не требует определенной версии и не переопределяет значение по умолчанию, если не указано иное.

Важно!

Созданные клиенты gRPC имеют синхронные и асинхронные методы для вызова унарных методов. Например, SayHello является синхронным, а SayHelloAsync — асинхронным. Асинхронные методы всегда требуются в Blazor WebAssembly. Вызов синхронного метода в приложении Blazor WebAssembly приведет к тому, что приложение перестанет отвечать на запросы.

Использование фабрики клиента gRPC с gRPC-Web

Создайте клиент .NET, совместимый с gRPC-Web, с помощью фабрики клиентов gRPC:

  • Добавьте ссылки на пакеты в файл проекта для следующих пакетов:
  • Зарегистрируйте клиент gRPC с внедрением зависимостей (DI) с помощью универсального метода расширения AddGrpcClient. В приложении Blazor WebAssembly службы регистрируются с внедрением зависимостей в Program.cs.
  • Настройте GrpcWebHandler с помощью метода расширения ConfigurePrimaryHttpMessageHandler.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

Дополнительные сведения см. в статье Интеграция фабрики клиента gRPC в .NET.

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