runtime: Exception of type 'Interop+AndroidCrypto+SslException' was thrown.
I want to connect to a gRPC service that is hosted in ASP Core application. All my projects are .NET 6.
In the client side, I have a a library that is the gRPC client, that receive the certificates of the client in a string format and then it creates the channel and the connection to the service. In this way, I can use this library in many clients, WPF, MAUI and so on.
When I use the WPF client, it works, I can connect with the remote server, but when I use the MAUI project, I get an error. Is this error:
Exception of type 'Interop+AndroidCrypto+SslException' was thrown.
{Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException: Authentication failed, see inner exception. SslException: Exception of type 'Interop+AndroidCrypto+SslException' was thrown.", DebugException="System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> Interop+AndroidCrypto+SslException: Exception of type 'Interop+AndroidCrypto+SslException' was thrown.
--- End of inner exception stack trace ---
at System.Net.Security.SslStream.<ForceAuthenticationAsync>d__175`1[[System.Net.Security.AsyncReadWriteAdapter, System.Net.Security, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]].MoveNext()
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.AddHttp2ConnectionAsync(HttpRequestMessage request)
at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.<WaitWithCancellationAsync>d__1[[System.Net.Http.Http2Connection, System.Net.Http, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]].MoveNext()
at System.Net.Http.HttpConnectionPool.GetHttp2ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Grpc.Net.Client.Internal.GrpcCall`2.<RunCall>d__73[[GestorOrdenadores.Service.Client.Grpc.HelloRequest, GestorOrdenadores.Service.Client.Grpc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[GestorOrdenadores.Service.Client.Grpc.HelloReply, GestorOrdenadores.Service.Client.Grpc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() in /_/src/Grpc.Net.Client/Internal/GrpcCall.cs:line 493")
at GestorOrdenadores.Service.Client.Grpc.ServiceClientGrpc.SayHelloAsync(String paramNombre) in D:\desarrollo\proyectos\GestorOrdenadores\GestorOrdenadores.Service.Client.Grpc\ServiceClientGrpc.cs:line 71
at GestorOrdenadores.Client.Maui.MainPage.OnBtnPingClicked(Object sender, EventArgs e) in D:\desarrollo\proyectos\GestorOrdenadores\GestorOrdenadores.Client.Maui\MainPage.xaml.cs:line 49}
The code of the library is this:
public class ServiceClientGrpc
{
#region constructores
public ServiceClientGrpc(string paramDireccion, int paramPuerto, string paramCertificado, string paramKey)
{
var cert = X509Certificate2.CreateFromPem(paramCertificado, paramKey);
paramDireccion = @"https://192.168.1.200";
paramPuerto = 5001;
HttpClientHandler miHttpHandler = new HttpClientHandler();
miHttpHandler.ClientCertificates.Add(cert);
HttpClient httpClient = new(miHttpHandler);
miHttpHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var channel = GrpcChannel.ForAddress(paramDireccion + ":" + paramPuerto, new GrpcChannelOptions
{
HttpClient = httpClient
});
_client = new Greeter.GreeterClient(channel);
}
#endregion constructores
private readonly Greeter.GreeterClient _client;
public async Task<string> SayHelloAsync(string paramNombre)
{
HelloRequest miRequest = new HelloRequest()
{
Name = paramNombre
};
return (await _client.SayHelloAsync(miRequest)).Message;
}
}
The WPF client:
private async void BtnSaludar_Click(object sender, RoutedEventArgs e)
{
try
{
string miStrCertificado = System.IO.File.ReadAllText(@"Certificados\Client.crt");
string miStrClave = System.IO.File.ReadAllText(@"Certificados\Client.key");
ServiceClientGrpc miService = new ServiceClientGrpc("https://192.168.1.200", 5001, miStrCertificado, miStrClave);
MessageBox.Show(await miService.SayHelloAsync("Álvaro"));
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The MAUI client:
private async void OnBtnSaludarClicked(object sender, EventArgs e)
{
try
{
//Get address and port from XML file.
string miStrDireccion = Configuracion.GestorConfiguracion.GetDireccionServicio();
int miStrPuerto = Configuracion.GestorConfiguracion.GetPuertoServicio();
//Get the certificates from Asserts files
using Stream miStmCertificado = await FileSystem.OpenAppPackageFileAsync("certificados/client.crt");
using StreamReader miSrCertificado = new StreamReader(miStmCertificado);
string miStrCertificado = await miSrCertificado.ReadToEndAsync();
using Stream miStmKey = await FileSystem.OpenAppPackageFileAsync("certificados/client.key");
using StreamReader miSrKey = new StreamReader(miStmKey);
string miStrKey = await miSrKey.ReadToEndAsync();
ServiceClientGrpc miServicio = new ServiceClientGrpc(miStrDireccion, miStrPuerto, miStrCertificado, miStrKey);
EtrRespuestaPing.Text = await miServicio.SayHelloAsync("Álvaro"); //Excetion in this line
}
catch(Exception ex)
{
await DisplayAlert("Alert", ex.Message, "OK");
}
}
From the android device in which I am debugging the MAUI project, I can ping the server with an application that pings.
Really the code is the same in WPF and MAUI, just I instantiate an object of type ServiceClientGrpc, passing the same data. Is ServiceClientGrpc who creates the channel and call the service.
In the past, when I tried this with Xamarin, I read that there was limitations in Xamarin, but I though that now MAUI can use Net 6, I had hope that I could use the same library for all the clients.
Is it not possible to use the same library for windows clients and android clients?
Thanks.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 21 (14 by maintainers)
Grpc.Core isn’t supported by Microsoft. It was created by the gRPC team. @ComptonAlvaro if you are using Grpc.Core then please ask questions for using it at grpc/grpc. No one at dotnet/runtime knows how it works.
Grpc.Net.Client currently doesn’t officially support MAUI+Android. Waiting on work in https://github.com/dotnet/runtime/issues/69095 before committing to supporting gRPC on Android.
In saying that, I’m pretty sure Grpc.Net.Client requires
SocketsHttpHandler
. That means either:SocketsHttpHandler
directlyHttpClientHandler
+ configuration to ensure it createsSocketsHttpHandler
internally (I don’t know the config name off the top of my head).When Android is supported, then I agree that gRPC+Android docs are required. There might also be the opportunity to detect at runtime that the current platform is Android and check that a valid handler is configured.