Как заставить GrpcChannel использовать HTTP/2 на MonoAndroid?
Я пытаюсь выполнить запрос к моему серверу по MagicOnion (он использует транспорт от gRPC, но другой протокол сериализации, message pack вместо protobuf).
Небольшой тестовый клиент, запускающийся под net5.0 выполняет примерно такой код:
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
var address = $"http://{ServerUrl.Host}:5002";
using var channel = GrpcChannel.ForAddress(address);
var myServiceClient = MagicOnionClient.Create<IMyService>(channel);
var result = await myServiceClient.GetMyData();
...и успешно получает ответ. Однако когда я пытаюсь выполнить в точности такой-же код на Android, я вижу такую ошибку в логе сервера:
Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2ConnectionErrorException: HTTP/2 connection error (PROTOCOL_ERROR): Invalid HTTP/2 connection preface.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2Connection.ParsePreface(ReadOnlySequence`1& buffer, SequencePosition& consumed, SequencePosition& examined)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2Connection.TryReadPrefaceAsync()
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2Connection.ProcessRequestsAsync[TContext](IHttpApplication`1 application)
По логам и дампу трафика видно что клиент на .Net 5 использует HTTP/2, а на Android - HTTP/1.1. На сколько я могу понять, это единственная разница между двумя запросами.
Как сделать так, чтобы клиент на Android (API 30, monoandroid10) использовал всё же HTTP/2?
Ответы (1 шт):
Решение состоит в том чтобы использовать другую библиотеку с реализацией GrpcChannel - Grpc.Core.
В моём случае она сразу не заработала, я получил ошибку связанную с загрузкой libgrpc_csharp_ext Чтобы она заработала в Xamarin, нужно так же подключить Grpc.Core.Xamarin той же версии, что и Grpc.Core. MagicOnionClient отлично работает с GrpcChannel из этой библиотеки.
Вот так выглядит рабочий пример:
var channel = new Grpc.Core.Channel(ServerUrl.Host, 5002, Grpc.Core.ChannelCredentials.Insecure);
var myServiceClient = MagicOnionClient.Create<IMyService>(channel);
var result = await myServiceClient.GetMyData();