我无法从xamarin发送请求,但可以从WPF应用程序发送请求

时间:2020-02-16 17:55:46

标签: c# xamarin xamarin.android grpc

我正在尝试从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应用程序起作用?

谢谢。

1 个答案:

答案 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?