Устранение неполадок gRPC в .NET

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

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

В этом документе рассматриваются часто возникающие проблемы при разработке приложений gRPC на платформе .NET.

Несоответствие конфигурации SSL/TLS клиента и службы

В шаблоне и образцах gRPC для защиты служб gRPC по умолчанию используется протокол TLS. Клиенты gRPC должны использовать безопасное соединение для успешного вызова защищенных служб gRPC.

Проверить, использует ли служба gRPC ASP.NET Core протокол TLS, можно в журналах, создаваемых при запуске приложения. Служба будет ожидать передачи данных через конечную точку HTTPS:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Для выполнения вызовов через защищенное соединение клиент .NET Core должен использовать https в адресе сервера:

var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);

Все реализации клиента gRPC поддерживают протокол TLS. Для клиентов gRPC на других языках обычно требуется канал, настроенный с помощью SslCredentials. В SslCredentials указывается сертификат, который будет использоваться клиентом вместо незащищенных учетных данных. Примеры настройки протокола TLS для различных реализаций клиента gRPC см. в статье, посвященной проверке подлинности gRPC.

Вызов службы gRPC с использованием ненадежного или недействительного сертификата

Клиент gRPC .NET требует, чтобы у службы был надежный сертификат. При вызове службы gRPC без надежного сертификата возвращается следующее сообщение об ошибке:

Необработанное исключение. System.Net.Http.HttpRequestException: не удалось установить ПОДКЛЮЧЕНИЕ SSL, см. внутреннее исключение. --->System.Security.AuthenticationException: удаленный сертификат является недопустимым согласно процедуре проверки.

Эта ошибка может возникать, если при локальном тестировании приложения сертификат разработки HTTPS ASP.NET Core не является надежным. См. сведения об устранении этой проблемы в руководстве по настройке доверия к сертификату разработки HTTPS ASP.NET Core в Windows и macOS.

Если вы вызываете службу gRPC на другом компьютере и не можете установить доверие к сертификату, то клиент gRPC можно настроить так, чтобы недействительный сертификат игнорировался. Следующий код используется HttpClientHandler.ServerCertificateCustomValidationCallback для разрешения вызовов без доверенного сертификата:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

Фабрика клиентов gRPC разрешает вызовы без доверенного сертификата. ConfigurePrimaryHttpMessageHandler Используйте метод расширения для настройки обработчика на клиенте:


var services = new ServiceCollection();

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback =
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Предупреждение

Ненадежные сертификаты следует использовать только во время разработки приложения. В рабочих приложениях всегда должны использоваться действительные сертификаты.

Вызов незащищенных служб gRPC с помощью клиента .NET Core

Клиент .NET gRPC может вызывать незащищенные службы gRPC, но для этого нужно указать http в адресе сервера. Например, GrpcChannel.ForAddress("http://localhost:5000").

Существуют дополнительные требования для вызова незащищенных служб gRPC в зависимости от версии .NET, используемой приложением:

Внимание

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

Не удается запустить приложение gRPC ASP.NET Core в macOS

Kestrel не поддерживает протокол HTTP/2 с TLS в macOS до .NET 8. В шаблоне и образцах gRPC ASP.NET Core по умолчанию используется протокол TLS. При попытке запустить сервер gRPC появится следующее сообщение об ошибке:

Не удается выполнить привязку к https://localhost:5001 интерфейсу обратного цикла IPv4: "HTTP/2 по протоколу TLS не поддерживается в macOS из-за отсутствия поддержки ALPN.

Чтобы обойти эту проблему в .NET 7 и более ранних версиях, настройте Kestrel и клиент gRPC для использования HTTP/2 без TLS. Это следует делать только во время разработки. Если протокол TLS не используется, сообщения gRPC передаются без шифрования. Дополнительные сведения см. в статье Asp.Net Core 7.0. Не удается запустить приложение ASP.NET Core gRPC в macOS.

Код ресурсов gRPC на C# не создается из файлов .proto

Для создания кода для конкретных клиентов и базовых классов службы gRPC необходимо, чтобы проект ссылался на файлы и инструментарий protobuf. Необходимо включить следующее:

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

Веб-приложение ASP.NET Core, в котором размещаются службы gRPC, требует создания только базового класса службы:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

Клиент gRPC, выполняющий вызовы gRPC, требует создания только конкретного клиента:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

В проектах WPF не удается создать ресурсы gRPC на C# из файлов .proto

В проектах WPF есть известная проблема, из-за которой создание кода gRPC работает неправильно. При использовании любых типов gRPC, созданных в проектах WPF посредством ссылки на Grpc.Tools и файлы .proto, будут возникать ошибки компиляции:

ошибка CS0246: не удалось найти имя типа или пространства имен MyGrpcServices (отсутствует директива using или ссылка на сборку?)

Эту проблему можно решить, выполнив указанные ниже действия.

  1. Создайте проект библиотеки классов .NET Core.
  2. В новом проекте добавьте ссылки на включение создания кода C# из .proto файлов:
  3. В приложении WPF добавьте ссылку на новый проект.

Приложение WPF может использовать созданные типы gRPC из нового проекта библиотеки классов.

Вызов служб gRPC, размещенных во вложенном каталоге

Предупреждение

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

Компонент пути в адресе канала gRPC игнорируется при выполнении вызовов gRPC. Например, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") не будет использовать ignored_path при маршрутизации вызовов gRPC для службы.

Путь к адресу игнорируется, так как gRPC имеет стандартизированную описательную структуру адресов. Адрес gRPC объединяет имена пакетов, служб и методов: https://localhost:5001/PackageName.ServiceName/MethodName.

Существует несколько сценариев, когда приложению необходимо включить путь с вызовами gRPC. Например, если приложение ASP.NET Core gRPC размещается в каталоге IIS, а каталог необходимо добавить в запрос. Если путь требуется, его можно добавить в вызов gRPC с помощью пользовательского экземпляра SubdirectoryHandler, указанного ниже:

public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler используется при создании канала gRPC.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

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

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

  • Создает SubdirectoryHandler с использованием пути /MyApp.
  • Настраивает канал для использования SubdirectoryHandler.
  • Вызывает службу gRPC с использованием SayHelloAsync. Вызов gRPC отправляется https://localhost:5001/MyApp/greet.Greeter/SayHello.

Кроме того, фабрику клиента можно настроить с SubdirectoryHandler с помощью AddHttpMessageHandler.

Настройка клиента gRPC для использования HTTP/3

Клиент .NET gRPC поддерживает HTTP/3 с .NET 6 или более поздней версии. Если сервер отправляет клиенту заголовок ответа alt-svc, указывающий, что сервер поддерживает HTTP/3, клиент автоматически обновит свое подключение до HTTP/3. Дополнительные сведения см. в разделе "Использование HTTP/3" с веб-сервером ASP.NET CoreKestrel.

Можно DelegatingHandler использовать для принудительного использования клиента gRPC для использования HTTP/3. Принудительное использование HTTP/3 позволяет избежать издержек, связанных с обновлением запроса. Принудительное использование HTTP/3 можно настроить с помощью следующего кода (пример):

public class Http3Handler : DelegatingHandler
{
    public Http3Handler() { }
    public Http3Handler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

        return base.SendAsync(request, cancellationToken);
    }
}

Http3Handler используется при создании канала gRPC. Следующий код создает канал, настроенный для использования Http3Handler.

var handler = new Http3Handler(new HttpClientHandler());

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greeter.GreeterClient(channel);

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

Кроме того, фабрику клиента можно настроить с Http3Handler с помощью AddHttpMessageHandler.

Создание gRPC в Alpine Linux

Пакет Grpc.Toolsсоздает типы .NET из .proto файлов с помощью встроенного двоичного файла protoc. Дополнительные шаги необходимы для создания приложений gRPC на платформах, которые не поддерживаются собственными двоичными файлами в Grpc.Tools, например Alpine Linux.

Создание кода перед временем

Одним из решений является создание кода перед временем.

  1. Перемещение .proto файлов и Grpc.Tools ссылки на пакет в новый проект.
  2. Опубликуйте проект как пакет NuGet и отправьте его в веб-канал NuGet.
  3. Обновите приложение, чтобы ссылаться на пакет NuGet.

С помощью предыдущих шагов приложение больше не требует Grpc.Tools сборки, так как код создается заранее.

Настройка Grpc.Tools собственных двоичных файлов

Grpc.Tools поддерживает использование пользовательских двоичных файлов в собственном коде. Эта функция позволяет инструменту gRPC запускаться в средах, в которые не поддерживаются встроенные двоичные файлы.

Создание или получение и grpc_csharp_plugin получение protoc собственных двоичных файлов и настройка Grpc.Tools их использования. Настройте собственные двоичные файлы, задав следующие переменные среды:

  • PROTOBUF_PROTOC — полный путь к компилятору буферов протокола
  • GRPC_PROTOC_PLUGIN — полный путь к grpc_csharp_plugin

Для Alpine Linux существуют пакеты, предоставляемые сообществом для компилятора и подключаемых модулей gRPC для буферов https://pkgs.alpinelinux.org/протокола.

# Build or install the binaries for your architecture.

# e.g. for Alpine Linux the grpc-plugins package can be used
#  See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
apk add grpc-plugins  # Alpine Linux specific package installer

# Set environment variables for the built/installed protoc
# and grpc_csharp_plugin binaries
export PROTOBUF_PROTOC=/usr/bin/protoc
export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin

# When dotnet build runs, the Grpc.Tools NuGet package
# uses the binaries pointed to by the environment variables.
dotnet build

Дополнительные сведения об использовании Grpc.Tools с неподдерживаемых архитектур см. в документации по интеграции сборки gRPC.

В этом документе рассматриваются часто возникающие проблемы при разработке приложений gRPC на платформе .NET.

Несоответствие конфигурации SSL/TLS клиента и службы

В шаблоне и образцах gRPC для защиты служб gRPC по умолчанию используется протокол TLS. Клиенты gRPC должны использовать безопасное соединение для успешного вызова защищенных служб gRPC.

Проверить, использует ли служба gRPC ASP.NET Core протокол TLS, можно в журналах, создаваемых при запуске приложения. Служба будет ожидать передачи данных через конечную точку HTTPS:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Для выполнения вызовов через защищенное соединение клиент .NET Core должен использовать https в адресе сервера:

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Все реализации клиента gRPC поддерживают протокол TLS. Для клиентов gRPC на других языках обычно требуется канал, настроенный с помощью SslCredentials. В SslCredentials указывается сертификат, который будет использоваться клиентом вместо незащищенных учетных данных. Примеры настройки протокола TLS для различных реализаций клиента gRPC см. в статье, посвященной проверке подлинности gRPC.

Вызов службы gRPC с использованием ненадежного или недействительного сертификата

Клиент gRPC .NET требует, чтобы у службы был надежный сертификат. При вызове службы gRPC без надежного сертификата возвращается следующее сообщение об ошибке:

Необработанное исключение. System.Net.Http.HttpRequestException: не удалось установить ПОДКЛЮЧЕНИЕ SSL, см. внутреннее исключение. --->System.Security.AuthenticationException: удаленный сертификат является недопустимым согласно процедуре проверки.

Эта ошибка может возникать, если при локальном тестировании приложения сертификат разработки HTTPS ASP.NET Core не является надежным. См. сведения об устранении этой проблемы в руководстве по настройке доверия к сертификату разработки HTTPS ASP.NET Core в Windows и macOS.

Если вы вызываете службу gRPC на другом компьютере и не можете установить доверие к сертификату, то клиент gRPC можно настроить так, чтобы недействительный сертификат игнорировался. Следующий код используется HttpClientHandler.ServerCertificateCustomValidationCallback для разрешения вызовов без доверенного сертификата:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

Фабрика клиентов gRPC разрешает вызовы без доверенного сертификата. ConfigurePrimaryHttpMessageHandler Используйте метод расширения для настройки обработчика на клиенте:

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Предупреждение

Ненадежные сертификаты следует использовать только во время разработки приложения. В рабочих приложениях всегда должны использоваться действительные сертификаты.

Вызов незащищенных служб gRPC с помощью клиента .NET Core

Клиент .NET gRPC может вызывать незащищенные службы gRPC, но для этого нужно указать http в адресе сервера. Например, GrpcChannel.ForAddress("http://localhost:5000").

Существуют дополнительные требования для вызова незащищенных служб gRPC в зависимости от версии .NET, используемой приложением:

  • Для .NET 5 или более поздней версии требуется Grpc.Net.Client версии 2.32.0 или более поздней.

  • Для .NET Core 3.x требуется дополнительная настройка. В приложении параметр System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport должен иметь значение true.

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Параметр System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport требуется только для .NET Core 3.x. Он не выполняет никаких действий в .NET 5 и не является обязательным.

Внимание

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

Не удается запустить приложение gRPC ASP.NET Core в macOS

Kestrel не поддерживает протокол HTTP/2 с TLS в macOS до .NET 8. В шаблоне и образцах gRPC ASP.NET Core по умолчанию используется протокол TLS. При попытке запустить сервер gRPC появится следующее сообщение об ошибке:

Не удается выполнить привязку к https://localhost:5001 интерфейсу обратного цикла IPv4: "HTTP/2 по протоколу TLS не поддерживается в macOS из-за отсутствия поддержки ALPN.

Чтобы обойти эту проблему в .NET 7 и более ранних версиях, настройте Kestrel и клиент gRPC для использования HTTP/2 без TLS. Это следует делать только во время разработки. Если протокол TLS не используется, сообщения gRPC передаются без шифрования.

Для Kestrel должна быть настроена конечная точка HTTP/2 без TLS в файле Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Setup a HTTP/2 endpoint without TLS.
    options.ListenLocalhost(<5287>, o => o.Protocols =
        HttpProtocols.Http2);
});
  • В предыдущем коде замените номер порта localhost 5287 номером порта HTTP (не HTTPS), указанным в файле Properties/launchSettings.json проекта службы gRPC.

Если конечная точка HTTP/2 настроена без TLS, для конечной точки ListenOptions.Protocols должно быть установлено значение HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 использовать нельзя, так как протокол TLS необходим для согласования подключения по HTTP/2. Без TLS все подключения к конечной точке по умолчанию осуществляются по протоколу HTTP/1.1, а вызовы gRPC завершаются ошибкой.

Клиент gRPC также должен быть настроен так, чтобы протокол TLS не использовался. Дополнительные сведения см. в разделе Вызов незащищенных служб gRPC с помощью клиента .NET Core.

Предупреждение

Протокол HTTP/2 без TLS следует использовать только во время разработки приложения. В рабочих приложениях всегда должна использоваться защита транспорта. Дополнительные сведения см. в статье Вопросы безопасности в gRPC для ASP.NET Core.

Код ресурсов gRPC на C# не создается из файлов .proto

Для создания кода для конкретных клиентов и базовых классов службы gRPC необходимо, чтобы проект ссылался на файлы и инструментарий protobuf. Необходимо включить следующее:

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

Веб-приложение ASP.NET Core, в котором размещаются службы gRPC, требует создания только базового класса службы:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

Клиент gRPC, выполняющий вызовы gRPC, требует создания только конкретного клиента:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

В проектах WPF не удается создать ресурсы gRPC на C# из файлов .proto

В проектах WPF есть известная проблема, из-за которой создание кода gRPC работает неправильно. При использовании любых типов gRPC, созданных в проектах WPF посредством ссылки на Grpc.Tools и файлы .proto, будут возникать ошибки компиляции:

ошибка CS0246: не удалось найти имя типа или пространства имен MyGrpcServices (отсутствует директива using или ссылка на сборку?)

Эту проблему можно решить, выполнив указанные ниже действия.

  1. Создайте проект библиотеки классов .NET Core.
  2. В новом проекте добавьте ссылки на включение создания кода C# из .proto файлов:
  3. В приложении WPF добавьте ссылку на новый проект.

Приложение WPF может использовать созданные типы gRPC из нового проекта библиотеки классов.

Вызов служб gRPC, размещенных во вложенном каталоге

Предупреждение

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

Компонент пути в адресе канала gRPC игнорируется при выполнении вызовов gRPC. Например, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") не будет использовать ignored_path при маршрутизации вызовов gRPC для службы.

Путь к адресу игнорируется, так как gRPC имеет стандартизированную описательную структуру адресов. Адрес gRPC объединяет имена пакетов, служб и методов: https://localhost:5001/PackageName.ServiceName/MethodName.

Существует несколько сценариев, когда приложению необходимо включить путь с вызовами gRPC. Например, если приложение ASP.NET Core gRPC размещается в каталоге IIS, а каталог необходимо добавить в запрос. Если путь требуется, его можно добавить в вызов gRPC с помощью пользовательского экземпляра SubdirectoryHandler, указанного ниже:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler используется при создании канала gRPC.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

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

  • Создает SubdirectoryHandler с использованием пути /MyApp.
  • Настраивает канал для использования SubdirectoryHandler.
  • Вызывает службу gRPC с использованием SayHelloAsync. Вызов gRPC отправляется https://localhost:5001/MyApp/greet.Greeter/SayHello.

Кроме того, фабрику клиента можно настроить с SubdirectoryHandler с помощью AddHttpMessageHandler.

Настройка клиента gRPC для использования HTTP/3

Клиент .NET gRPC поддерживает HTTP/3 с .NET 6 или более поздней версии. Если сервер отправляет клиенту заголовок ответа alt-svc, указывающий, что сервер поддерживает HTTP/3, клиент автоматически обновит свое подключение до HTTP/3. Сведения о том, как включить HTTP/3 на сервере, см. в статье Использование HTTP/3 с веб-сервером Kestrel для ASP.NET Core.

Поддержка HTTP/3 в .NET 8 включена по умолчанию. Поддержка HTTP/3 в .NET 6 и .NET 7 должна быть включена с помощью флага конфигурации в файле проекта:

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Net.SocketsHttpHandler.Http3Support" Value="true" />
</ItemGroup>

System.Net.SocketsHttpHandler.Http3Support также можно задать с использованием AppContext.SetSwitch.

Можно DelegatingHandler использовать для принудительного использования клиента gRPC для использования HTTP/3. Принудительное использование HTTP/3 позволяет избежать издержек, связанных с обновлением запроса. Принудительное использование HTTP/3 можно настроить с помощью следующего кода (пример):

/// <summary>
/// A delegating handler that changes the request HTTP version to HTTP/3.
/// </summary>
public class Http3Handler : DelegatingHandler
{
    public Http3Handler() { }
    public Http3Handler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version30;
        request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;

        return base.SendAsync(request, cancellationToken);
    }
}

Http3Handler используется при создании канала gRPC. Следующий код создает канал, настроенный для использования Http3Handler.

var handler = new Http3Handler(new HttpClientHandler());

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

Кроме того, фабрику клиента можно настроить с Http3Handler с помощью AddHttpMessageHandler.

Создание gRPC в Alpine Linux

Пакет Grpc.Toolsсоздает типы .NET из .proto файлов с помощью встроенного двоичного файла protoc. Дополнительные шаги необходимы для создания приложений gRPC на платформах, которые не поддерживаются собственными двоичными файлами в Grpc.Tools, например Alpine Linux.

Создание кода перед временем

Одним из решений является создание кода перед временем.

  1. Перемещение .proto файлов и Grpc.Tools ссылки на пакет в новый проект.
  2. Опубликуйте проект как пакет NuGet и отправьте его в веб-канал NuGet.
  3. Обновите приложение, чтобы ссылаться на пакет NuGet.

С помощью предыдущих шагов приложение больше не требует Grpc.Tools сборки, так как код создается заранее.

Настройка Grpc.Tools собственных двоичных файлов

Grpc.Tools поддерживает использование пользовательских двоичных файлов в собственном коде. Эта функция позволяет инструменту gRPC запускаться в средах, в которые не поддерживаются встроенные двоичные файлы.

Создание или получение и grpc_csharp_plugin получение protoc собственных двоичных файлов и настройка Grpc.Tools их использования. Настройте собственные двоичные файлы, задав следующие переменные среды:

  • PROTOBUF_PROTOC — полный путь к компилятору буферов протокола
  • GRPC_PROTOC_PLUGIN — полный путь к grpc_csharp_plugin

Для Alpine Linux существуют пакеты, предоставляемые сообществом для компилятора и подключаемых модулей gRPC для буферов https://pkgs.alpinelinux.org/протокола.

# Build or install the binaries for your architecture.

# e.g. for Alpine Linux the grpc-plugins package can be used
#  See https://pkgs.alpinelinux.org/package/edge/community/x86_64/grpc-plugins
apk add grpc-plugins  # Alpine Linux specific package installer

# Set environment variables for the built/installed protoc
# and grpc_csharp_plugin binaries
export PROTOBUF_PROTOC=/usr/bin/protoc
export GRPC_PROTOC_PLUGIN=/usr/bin/grpc_csharp_plugin

# When dotnet build runs, the Grpc.Tools NuGet package
# uses the binaries pointed to by the environment variables.
dotnet build

Дополнительные сведения об использовании Grpc.Tools с неподдерживаемых архитектур см. в документации по интеграции сборки gRPC.

В этом документе рассматриваются часто возникающие проблемы при разработке приложений gRPC на платформе .NET.

Несоответствие конфигурации SSL/TLS клиента и службы

В шаблоне и образцах gRPC для защиты служб gRPC по умолчанию используется протокол TLS. Клиенты gRPC должны использовать безопасное соединение для успешного вызова защищенных служб gRPC.

Проверить, использует ли служба gRPC ASP.NET Core протокол TLS, можно в журналах, создаваемых при запуске приложения. Служба будет ожидать передачи данных через конечную точку HTTPS:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Для выполнения вызовов через защищенное соединение клиент .NET Core должен использовать https в адресе сервера:

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Все реализации клиента gRPC поддерживают протокол TLS. Для клиентов gRPC на других языках обычно требуется канал, настроенный с помощью SslCredentials. В SslCredentials указывается сертификат, который будет использоваться клиентом вместо незащищенных учетных данных. Примеры настройки протокола TLS для различных реализаций клиента gRPC см. в статье, посвященной проверке подлинности gRPC.

Вызов службы gRPC с использованием ненадежного или недействительного сертификата

Клиент gRPC .NET требует, чтобы у службы был надежный сертификат. При вызове службы gRPC без надежного сертификата возвращается следующее сообщение об ошибке:

Необработанное исключение. System.Net.Http.HttpRequestException: не удалось установить ПОДКЛЮЧЕНИЕ SSL, см. внутреннее исключение. --->System.Security.AuthenticationException: удаленный сертификат является недопустимым согласно процедуре проверки.

Эта ошибка может возникать, если при локальном тестировании приложения сертификат разработки HTTPS ASP.NET Core не является надежным. См. сведения об устранении этой проблемы в руководстве по настройке доверия к сертификату разработки HTTPS ASP.NET Core в Windows и macOS.

Если вы вызываете службу gRPC на другом компьютере и не можете установить доверие к сертификату, то клиент gRPC можно настроить так, чтобы недействительный сертификат игнорировался. Следующий код используется HttpClientHandler.ServerCertificateCustomValidationCallback для разрешения вызовов без доверенного сертификата:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

Фабрика клиентов gRPC разрешает вызовы без доверенного сертификата. ConfigurePrimaryHttpMessageHandler Используйте метод расширения для настройки обработчика на клиенте:

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Предупреждение

Ненадежные сертификаты следует использовать только во время разработки приложения. В рабочих приложениях всегда должны использоваться действительные сертификаты.

Вызов незащищенных служб gRPC с помощью клиента .NET Core

Клиент .NET gRPC может вызывать незащищенные службы gRPC, но для этого нужно указать http в адресе сервера. Например, GrpcChannel.ForAddress("http://localhost:5000").

Существуют дополнительные требования для вызова незащищенных служб gRPC в зависимости от версии .NET, используемой приложением:

  • Для .NET 5 или более поздней версии требуется Grpc.Net.Client версии 2.32.0 или более поздней.

  • Для .NET Core 3.x требуется дополнительная настройка. В приложении параметр System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport должен иметь значение true.

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Параметр System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport требуется только для .NET Core 3.x. Он не выполняет никаких действий в .NET 5 и не является обязательным.

Внимание

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

Не удается запустить приложение gRPC ASP.NET Core в macOS

Kestrel не поддерживает протокол HTTP/2 с TLS в macOS до .NET 8. В шаблоне и образцах gRPC ASP.NET Core по умолчанию используется протокол TLS. При попытке запустить сервер gRPC появится следующее сообщение об ошибке:

Не удается выполнить привязку к https://localhost:5001 интерфейсу обратного цикла IPv4: "HTTP/2 по протоколу TLS не поддерживается в macOS из-за отсутствия поддержки ALPN.

Чтобы обойти эту проблему в .NET 7 и более ранних версиях, настройте Kestrel и клиент gRPC для использования HTTP/2 без TLS. Это следует делать только во время разработки. Если протокол TLS не используется, сообщения gRPC передаются без шифрования.

Для Kestrel должна быть настроена конечная точка HTTP/2 без TLS в файле Program.cs:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                // Setup a HTTP/2 endpoint without TLS.
                options.ListenLocalhost(5000, o => o.Protocols = 
                    HttpProtocols.Http2);
            });
            webBuilder.UseStartup<Startup>();
        });

Если конечная точка HTTP/2 настроена без TLS, для конечной точки ListenOptions.Protocols должно быть установлено значение HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 использовать нельзя, так как протокол TLS необходим для согласования подключения по HTTP/2. Без TLS все подключения к конечной точке по умолчанию осуществляются по протоколу HTTP/1.1, а вызовы gRPC завершаются ошибкой.

Клиент gRPC также должен быть настроен так, чтобы протокол TLS не использовался. Дополнительные сведения см. в разделе Вызов незащищенных служб gRPC с помощью клиента .NET Core.

Предупреждение

Протокол HTTP/2 без TLS следует использовать только во время разработки приложения. В рабочих приложениях всегда должна использоваться защита транспорта. Дополнительные сведения см. в статье Вопросы безопасности в gRPC для ASP.NET Core.

Код ресурсов gRPC на C# не создается из файлов .proto

Для создания кода для конкретных клиентов и базовых классов службы gRPC необходимо, чтобы проект ссылался на файлы и инструментарий protobuf. Необходимо включить следующее:

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

Веб-приложение ASP.NET Core, в котором размещаются службы gRPC, требует создания только базового класса службы:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

Клиент gRPC, выполняющий вызовы gRPC, требует создания только конкретного клиента:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

В проектах WPF не удается создать ресурсы gRPC на C# из файлов .proto

В проектах WPF есть известная проблема, из-за которой создание кода gRPC работает неправильно. При использовании любых типов gRPC, созданных в проектах WPF посредством ссылки на Grpc.Tools и файлы .proto, будут возникать ошибки компиляции:

ошибка CS0246: не удалось найти имя типа или пространства имен MyGrpcServices (отсутствует директива using или ссылка на сборку?)

Эту проблему можно решить, выполнив указанные ниже действия.

  1. Создайте проект библиотеки классов .NET Core.
  2. В новом проекте добавьте ссылки на включение создания кода C# из .proto файлов:
  3. В приложении WPF добавьте ссылку на новый проект.

Приложение WPF может использовать созданные типы gRPC из нового проекта библиотеки классов.

Вызов служб gRPC, размещенных во вложенном каталоге

Предупреждение

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

Компонент пути в адресе канала gRPC игнорируется при выполнении вызовов gRPC. Например, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") не будет использовать ignored_path при маршрутизации вызовов gRPC для службы.

Путь к адресу игнорируется, так как gRPC имеет стандартизированную описательную структуру адресов. Адрес gRPC объединяет имена пакетов, служб и методов: https://localhost:5001/PackageName.ServiceName/MethodName.

Существует несколько сценариев, когда приложению необходимо включить путь с вызовами gRPC. Например, если приложение ASP.NET Core gRPC размещается в каталоге IIS, а каталог необходимо добавить в запрос. Если путь требуется, его можно добавить в вызов gRPC с помощью пользовательского экземпляра SubdirectoryHandler, указанного ниже:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler используется при создании канала gRPC.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

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

  • Создает SubdirectoryHandler с использованием пути /MyApp.
  • Настраивает канал для использования SubdirectoryHandler.
  • Вызывает службу gRPC с использованием SayHelloAsync. Вызов gRPC отправляется https://localhost:5001/MyApp/greet.Greeter/SayHello.

Кроме того, фабрику клиента можно настроить с SubdirectoryHandler с помощью AddHttpMessageHandler.

В этом документе рассматриваются часто возникающие проблемы при разработке приложений gRPC на платформе .NET.

Несоответствие конфигурации SSL/TLS клиента и службы

В шаблоне и образцах gRPC для защиты служб gRPC по умолчанию используется протокол TLS. Клиенты gRPC должны использовать безопасное соединение для успешного вызова защищенных служб gRPC.

Проверить, использует ли служба gRPC ASP.NET Core протокол TLS, можно в журналах, создаваемых при запуске приложения. Служба будет ожидать передачи данных через конечную точку HTTPS:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development

Для выполнения вызовов через защищенное соединение клиент .NET Core должен использовать https в адресе сервера:

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client = new Greet.GreeterClient(channel);
}

Все реализации клиента gRPC поддерживают протокол TLS. Для клиентов gRPC на других языках обычно требуется канал, настроенный с помощью SslCredentials. В SslCredentials указывается сертификат, который будет использоваться клиентом вместо незащищенных учетных данных. Примеры настройки протокола TLS для различных реализаций клиента gRPC см. в статье, посвященной проверке подлинности gRPC.

Вызов службы gRPC с использованием ненадежного или недействительного сертификата

Клиент gRPC .NET требует, чтобы у службы был надежный сертификат. При вызове службы gRPC без надежного сертификата возвращается следующее сообщение об ошибке:

Необработанное исключение. System.Net.Http.HttpRequestException: не удалось установить ПОДКЛЮЧЕНИЕ SSL, см. внутреннее исключение. --->System.Security.AuthenticationException: удаленный сертификат является недопустимым согласно процедуре проверки.

Эта ошибка может возникать, если при локальном тестировании приложения сертификат разработки HTTPS ASP.NET Core не является надежным. См. сведения об устранении этой проблемы в руководстве по настройке доверия к сертификату разработки HTTPS ASP.NET Core в Windows и macOS.

Если вы вызываете службу gRPC на другом компьютере и не можете установить доверие к сертификату, то клиент gRPC можно настроить так, чтобы недействительный сертификат игнорировался. Следующий код используется HttpClientHandler.ServerCertificateCustomValidationCallback для разрешения вызовов без доверенного сертификата:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

Фабрика клиентов gRPC разрешает вызовы без доверенного сертификата. ConfigurePrimaryHttpMessageHandler Используйте метод расширения для настройки обработчика на клиенте:

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ServerCertificateCustomValidationCallback = 
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

        return handler;
    });

Предупреждение

Ненадежные сертификаты следует использовать только во время разработки приложения. В рабочих приложениях всегда должны использоваться действительные сертификаты.

Вызов незащищенных служб gRPC с помощью клиента .NET Core

Клиент .NET gRPC может вызывать незащищенные службы gRPC, но для этого нужно указать http в адресе сервера. Например, GrpcChannel.ForAddress("http://localhost:5000").

Существуют дополнительные требования для вызова незащищенных служб gRPC в зависимости от версии .NET, используемой приложением:

  • Для .NET 5 или более поздней версии требуется Grpc.Net.Client версии 2.32.0 или более поздней.

  • Для .NET Core 3.x требуется дополнительная настройка. В приложении параметр System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport должен иметь значение true.

    // This switch must be set before creating the GrpcChannel/HttpClient.
    AppContext.SetSwitch(
        "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    
    // The port number(5000) must match the port of the gRPC server.
    var channel = GrpcChannel.ForAddress("http://localhost:5000");
    var client = new Greet.GreeterClient(channel);
    

Параметр System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport требуется только для .NET Core 3.x. Он не выполняет никаких действий в .NET 5 и не является обязательным.

Внимание

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

Не удается запустить приложение gRPC ASP.NET Core в macOS

Kestrel не поддерживает протокол HTTP/2 с TLS в macOS до .NET 8. В шаблоне и образцах gRPC ASP.NET Core по умолчанию используется протокол TLS. При попытке запустить сервер gRPC появится следующее сообщение об ошибке:

Не удается выполнить привязку к https://localhost:5001 интерфейсу обратного цикла IPv4: "HTTP/2 по протоколу TLS не поддерживается в macOS из-за отсутствия поддержки ALPN.

Чтобы обойти эту проблему в .NET 7 и более ранних версиях, настройте Kestrel и клиент gRPC для использования HTTP/2 без TLS. Это следует делать только во время разработки. Если протокол TLS не используется, сообщения gRPC передаются без шифрования.

Для Kestrel должна быть настроена конечная точка HTTP/2 без TLS в файле Program.cs:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                // Setup a HTTP/2 endpoint without TLS.
                options.ListenLocalhost(5000, o => o.Protocols = 
                    HttpProtocols.Http2);
            });
            webBuilder.UseStartup<Startup>();
        });

Если конечная точка HTTP/2 настроена без TLS, для конечной точки ListenOptions.Protocols должно быть установлено значение HttpProtocols.Http2. HttpProtocols.Http1AndHttp2 использовать нельзя, так как протокол TLS необходим для согласования подключения по HTTP/2. Без TLS все подключения к конечной точке по умолчанию осуществляются по протоколу HTTP/1.1, а вызовы gRPC завершаются ошибкой.

Клиент gRPC также должен быть настроен так, чтобы протокол TLS не использовался. Дополнительные сведения см. в разделе Вызов незащищенных служб gRPC с помощью клиента .NET Core.

Предупреждение

Протокол HTTP/2 без TLS следует использовать только во время разработки приложения. В рабочих приложениях всегда должна использоваться защита транспорта. Дополнительные сведения см. в статье Вопросы безопасности в gRPC для ASP.NET Core.

Код ресурсов gRPC на C# не создается из файлов .proto

Для создания кода для конкретных клиентов и базовых классов службы gRPC необходимо, чтобы проект ссылался на файлы и инструментарий protobuf. Необходимо включить следующее:

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

Веб-приложение ASP.NET Core, в котором размещаются службы gRPC, требует создания только базового класса службы:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

Клиент gRPC, выполняющий вызовы gRPC, требует создания только конкретного клиента:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>

В проектах WPF не удается создать ресурсы gRPC на C# из файлов .proto

В проектах WPF есть известная проблема, из-за которой создание кода gRPC работает неправильно. При использовании любых типов gRPC, созданных в проектах WPF посредством ссылки на Grpc.Tools и файлы .proto, будут возникать ошибки компиляции:

ошибка CS0246: не удалось найти имя типа или пространства имен MyGrpcServices (отсутствует директива using или ссылка на сборку?)

Эту проблему можно решить, выполнив указанные ниже действия.

  1. Создайте проект библиотеки классов .NET Core.
  2. В новом проекте добавьте ссылки на включение создания кода C# из .proto файлов:
  3. В приложении WPF добавьте ссылку на новый проект.

Приложение WPF может использовать созданные типы gRPC из нового проекта библиотеки классов.

Вызов служб gRPC, размещенных во вложенном каталоге

Предупреждение

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

Компонент пути в адресе канала gRPC игнорируется при выполнении вызовов gRPC. Например, GrpcChannel.ForAddress("https://localhost:5001/ignored_path") не будет использовать ignored_path при маршрутизации вызовов gRPC для службы.

Путь к адресу игнорируется, так как gRPC имеет стандартизированную описательную структуру адресов. Адрес gRPC объединяет имена пакетов, служб и методов: https://localhost:5001/PackageName.ServiceName/MethodName.

Существует несколько сценариев, когда приложению необходимо включить путь с вызовами gRPC. Например, если приложение ASP.NET Core gRPC размещается в каталоге IIS, а каталог необходимо добавить в запрос. Если путь требуется, его можно добавить в вызов gRPC с помощью пользовательского экземпляра SubdirectoryHandler, указанного ниже:

/// <summary>
/// A delegating handler that adds a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
    private readonly string _subdirectory;

    public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory)
        : base(innerHandler)
    {
        _subdirectory = subdirectory;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var old = request.RequestUri;

        var url = $"{old.Scheme}://{old.Host}:{old.Port}";
        url += $"{_subdirectory}{request.RequestUri.AbsolutePath}";
        request.RequestUri = new Uri(url, UriKind.Absolute);

        return base.SendAsync(request, cancellationToken);
    }
}

SubdirectoryHandler используется при создании канала gRPC.

var handler = new SubdirectoryHandler(new HttpClientHandler(), "/MyApp");

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = handler });
var client = new Greet.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

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

  • Создает SubdirectoryHandler с использованием пути /MyApp.
  • Настраивает канал для использования SubdirectoryHandler.
  • Вызывает службу gRPC с использованием SayHelloAsync. Вызов gRPC отправляется https://localhost:5001/MyApp/greet.Greeter/SayHello.

Кроме того, фабрику клиента можно настроить с SubdirectoryHandler с помощью AddHttpMessageHandler.