Устранение неполадок gRPC в .NET
Автор: Джеймс Ньютон-Кинг (James Newton-King)
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в статье о политике поддержки .NET и .NET Core. В текущем выпуске см . версию .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, используемой приложением:
- Для .NET 5 или более поздней версии требуется Grpc.Net.Client версии 2.32.0 или более поздней.
- Для .NET Core 3.x требуется дополнительная настройка. Приложение должно задать для параметра переключатель
System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport
true
. Дополнительные сведения см. в разделе Asp.Net Core 3.x. Вызов небезопасных служб 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. Необходимо включить следующее:
- Нужные файлы
.proto
в группе элементов<Protobuf>
. Проект должен ссылаться на импортированные файлы.proto
. - ссылку на пакет инструментария gRPC Grpc.Tools.
Дополнительные сведения о создании ресурсов 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 или ссылка на сборку?)
Эту проблему можно решить, выполнив указанные ниже действия.
- Создайте проект библиотеки классов .NET Core.
- В новом проекте добавьте ссылки на включение создания кода C# из
.proto
файлов:- Добавьте следующие ссылки на пакет:
- Добавьте файлы
.proto
в группу элементов<Protobuf>
.
- В приложении 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.
Создание кода перед временем
Одним из решений является создание кода перед временем.
- Перемещение
.proto
файлов иGrpc.Tools
ссылки на пакет в новый проект. - Опубликуйте проект как пакет NuGet и отправьте его в веб-канал NuGet.
- Обновите приложение, чтобы ссылаться на пакет 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.
# 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 из HttpClient.Timeout
HttpClient по умолчанию настроено 100 секундное время ожидания. GrpcChannel
Если настроено использовать HttpClient
длительные вызовы потоковой передачи gRPC, отменяются, если они не завершаются в течение срока ожидания.
System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.
Существует несколько способов устранения этой ошибки. Первое — настроить HttpClient.Timeout для большего значения. Timeout.InfiniteTimeSpan отключает время ожидания:
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);
Кроме того, избегайте создания HttpClient
и задания GrpcChannel.HttpHandler
вместо этого:
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 на платформе .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. Необходимо включить следующее:
- Нужные файлы
.proto
в группе элементов<Protobuf>
. Проект должен ссылаться на импортированные файлы.proto
. - ссылку на пакет инструментария gRPC Grpc.Tools.
Дополнительные сведения о создании ресурсов 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 или ссылка на сборку?)
Эту проблему можно решить, выполнив указанные ниже действия.
- Создайте проект библиотеки классов .NET Core.
- В новом проекте добавьте ссылки на включение создания кода C# из
.proto
файлов:- Добавьте следующие ссылки на пакет:
- Добавьте файлы
.proto
в группу элементов<Protobuf>
.
- В приложении 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.
Создание кода перед временем
Одним из решений является создание кода перед временем.
- Перемещение
.proto
файлов иGrpc.Tools
ссылки на пакет в новый проект. - Опубликуйте проект как пакет NuGet и отправьте его в веб-канал NuGet.
- Обновите приложение, чтобы ссылаться на пакет 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.
# 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 из HttpClient.Timeout
HttpClient по умолчанию настроено 100 секундное время ожидания. GrpcChannel
Если настроено использовать HttpClient
длительные вызовы потоковой передачи gRPC, отменяются, если они не завершаются в течение срока ожидания.
System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.
Существует несколько способов устранения этой ошибки. Первое — настроить HttpClient.Timeout для большего значения. Timeout.InfiniteTimeSpan отключает время ожидания:
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);
Кроме того, избегайте создания HttpClient
и задания GrpcChannel.HttpHandler
вместо этого:
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 на платформе .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. Необходимо включить следующее:
- Нужные файлы
.proto
в группе элементов<Protobuf>
. Проект должен ссылаться на импортированные файлы.proto
. - ссылку на пакет инструментария gRPC Grpc.Tools.
Дополнительные сведения о создании ресурсов 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 или ссылка на сборку?)
Эту проблему можно решить, выполнив указанные ниже действия.
- Создайте проект библиотеки классов .NET Core.
- В новом проекте добавьте ссылки на включение создания кода C# из
.proto
файлов:- Добавьте следующие ссылки на пакет:
- Добавьте файлы
.proto
в группу элементов<Protobuf>
.
- В приложении 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 из HttpClient.Timeout
HttpClient по умолчанию настроено 100 секундное время ожидания. GrpcChannel
Если настроено использовать HttpClient
длительные вызовы потоковой передачи gRPC, отменяются, если они не завершаются в течение срока ожидания.
System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.
Существует несколько способов устранения этой ошибки. Первое — настроить HttpClient.Timeout для большего значения. Timeout.InfiniteTimeSpan отключает время ожидания:
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);
Кроме того, избегайте создания HttpClient
и задания GrpcChannel.HttpHandler
вместо этого:
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 на платформе .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. Необходимо включить следующее:
- Нужные файлы
.proto
в группе элементов<Protobuf>
. Проект должен ссылаться на импортированные файлы.proto
. - ссылку на пакет инструментария gRPC Grpc.Tools.
Дополнительные сведения о создании ресурсов 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 или ссылка на сборку?)
Эту проблему можно решить, выполнив указанные ниже действия.
- Создайте проект библиотеки классов .NET Core.
- В новом проекте добавьте ссылки на включение создания кода C# из
.proto
файлов:- Добавьте следующие ссылки на пакет:
- Добавьте файлы
.proto
в группу элементов<Protobuf>
.
- В приложении 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 из HttpClient.Timeout
HttpClient по умолчанию настроено 100 секундное время ожидания. GrpcChannel
Если настроено использовать HttpClient
длительные вызовы потоковой передачи gRPC, отменяются, если они не завершаются в течение срока ожидания.
System.OperationCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.
Существует несколько способов устранения этой ошибки. Первое — настроить HttpClient.Timeout для большего значения. Timeout.InfiniteTimeSpan отключает время ожидания:
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan };
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);
Кроме того, избегайте создания HttpClient
и задания GrpcChannel.HttpHandler
вместо этого:
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);
ASP.NET Core