【问题标题】:I can't send a request from xamarin but I can send the request from WPF application我无法从 xamarin 发送请求,但我可以从 WPF 应用程序发送请求
【发布时间】:2020-05-31 17:39:53
【问题描述】:

我正在尝试从 android 向 gRPC 服务发送请求。使用在同一台计算机上运行的 WPF 网络核心应用程序,它可以工作,但在 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 应用程序。

为什么请求来自 WPF 应用程序而不是来自 xamarin 应用程序?

谢谢。

【问题讨论】:

  • 您是否遇到异常或错误?这些是什么?您是否验证过您的服务器可以从您的 Android 设备访问?您是否已将应用配置为允许非 https 请求?
  • 我在 android 设备中安装了一个 ping 应用程序,我得到了响应。我试图不安全的凭据,所以服务是 http 而不是 https,但问题是一样的。无论如何,我想学习如何使用凭证和 SSL 证书。
  • 关于 Xamarin.forms 中带有凭据的 https,也许你可以阅读 HTTPS Service With Self-Signed Certificate
  • xamarin 内部使用的 SocketsHttpHandler 似乎是不支持 Http2 的旧版本。您可以使用wireshark 以及通过调查android 上的grpc 通道使用的HttpClient 来看到这一点。
  • stackoverflow.com/questions/60100916/… 我正在解决最近有人在 Stackoverflow 上报告的这个问题。上面的答案似乎不完整。我试图将此调试到 xamarin-android 代码。很难了解它的内部结构,因为它是一个具有复杂依赖关系的大型存储库。如果我设法解决,将发布答案。

标签: c# xamarin xamarin.android grpc


【解决方案1】:

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 支持。

对我来说,由于这个问题,不仅 Grpc,而且任何 Http2 请求在 xamarin android 上都会失败。 Why does Xamarin Android fails to send GRPC/Http2 requests?

【讨论】:

  • 非常感谢。如果我使用这种方式,我会收到错误 DNS 解析失败,在这种情况下,它也会发生在 WPF 客户端中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-11
  • 2023-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多