我正在尝试从android向gRPC服务发送请求。在同一台计算机上运行WPF net core的应用程序可以运行,但是从android不能运行。另外,我已经在另一台计算机(虚拟机)中尝试了此WPF应用程序,它也可以正常工作。
我的xamarion应用程序代码:
private void SetVariablesServicio()
{
_serviceAddress = "http://1.2.3.4:5001";
using (StreamReader miCertificado = new StreamReader(Assets.Open("CA.crt")))
{
_caCertificate = miCertificado.ReadToEnd();
}
using (StreamReader miCertificado = new StreamReader(Assets.Open("Client.crt")))
{
_clientCertificate = miCertificado.ReadToEnd();
}
using (StreamReader miCertificado = new StreamReader(Assets.Open("Client.key")))
{
_clientPrivateKey = miCertificado.ReadToEnd();
}
}
private async void btnTestServicio_Click()
{
try
{
GrpcClient.GestorAplicaciones miGrpcClient = new GrpcClient.GestorAplicaciones(_serviceAddress, _caCertificate, _clientCertificate, _clientPrivateKey);
string miSaludo = await miGrpcClient.PingAsync("Álvaro");
ShowAlert("Error", miSaludo);
}
catch (Exception ex)
{
ShowAlert("Error", ex.Message);
}
}
gRPC客户端的公共库:
public class GestorAplicaciones
{
#region constructor
public GestorAplicaciones(string paramAddressService, string paramStrCertificadoCa, string paramStrCertificadoCliente, string paramStrClaveCertificadoCliente)
{
_serviceAddress = paramAddressService;
_caCertificate = paramStrCertificadoCa;
_clientCertificate = paramStrCertificadoCliente;
_clientPrivateKey = paramStrClaveCertificadoCliente;
}
#endregion constructor
#region variables de clase
private string _serviceAddress;
private string _caCertificate;
private string _clientPrivateKey;
private string _clientCertificate;
#endregion variables de clase
#region método de llamada al servicio
public async Task<string> PingAsync(string paramStrNombreLlamante)
{
Gestor.GestorClient miClienteGrpc = GetClient();
PingRequest input = new PingRequest { NomreLlamante = paramStrNombreLlamante };
var reply = await miClienteGrpc.PingAsync(input);
return reply.MensajeRespuesta;
}
private Gestor.GestorClient GetClient()
{
var httpClientHandler = new System.Net.Http.HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback =
System.Net.Http.HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new System.Net.Http.HttpClient(httpClientHandler);
var channel = GrpcChannel.ForAddress(_serviceAddress,
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Gestor.GestorClient(channel);
return client;
}
WPF客户端:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_serviceAddress = "https://1.2.3.4:5001";
_caCertificate = System.IO.File.ReadAllText("certificados/ca.crt");
_clientPrivateKey = System.IO.File.ReadAllText("certificados/client.key");
_clientCertificate = System.IO.File.ReadAllText("certificados/client.crt");
}
#region variables de clase
private readonly string _serviceAddress;
private readonly string _caCertificate;
private readonly string _clientPrivateKey;
private readonly string _clientCertificate;
#endregion variables de clase
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
GrpcClient.GestorAplicaciones miGrpcClient = new GrpcClient.GestorAplicaciones(_serviceAddress, _caCertificate, _clientCertificate, _clientPrivateKey);
string miSaludo = await miGrpcClient.PingAsync("Álvaro");
MessageBox.Show(miSaludo);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
服务:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(options =>
{
//NOTA: se tiene que poner la IP porque si no, se dice que el equipo remoto ha denegado la conexión.
options.Listen(miAddress, 5001, o =>
{
o.Protocols = HttpProtocols.Http2;
o.UseHttps(@"certificados\service.pfx", "123456");
});
})
.ConfigureLogging(logging =>
{
logging.AddFilter("Grpc", LogLevel.Debug);
});
webBuilder.UseStartup<Startup>();
});
}
我的想法是为客户端提供一个公共库,供xamarin和wpf客户端使用。
我正在调试xamarion应用程序,将其部署在Android手机中。
为什么请求从WPF应用程序而不是xamarin应用程序起作用?
谢谢。
答案 0 :(得分:2)
Grpc.Net在Xamarin上失败,因为似乎在通过Monodroid上的System.Net.Http.HttpClientHandler发送HTTP2流量时出现问题。
您可以做的是,将依赖项添加到Grpc.Core nuget并通过它创建grpc客户端。该API的其余部分几乎是共享的(两个库都共享Grpc.Core.Api nuget)。
// For secured grpc service
var channel = new Channel("1.2.3.4:5001", new SslCredentials());
// cleartext
var channel = new Channel("1.2.3.4:5001", ChannelCredentials.Insecure);
请自行研究如何创建ChannelCredentials实例。上面的代码对我有用,但是我不确定它是否在所有情况下都适用。
您可以删除Grpc.Net.Client nuget依赖项。确保也将Grpc.Core依赖项添加到Xamarin.Android项目中。
Grpc.Core起作用的原因是因为它是用c ++编写的核心grpc客户端库的托管包装。因此,它不依赖mono / .net的Http支持。
对我来说,由于此问题,不仅在xamarin android上,不仅Grpc而且所有Http2请求都失败。 Why does Xamarin Android fails to send GRPC/Http2 requests?