我开发了一个简单的 ASP .NET 6 后端服务器,它通过 gRPC 提供服务。我还编写了一个基本的 WPF 桌面应用程序和一个简单的 .NET MAUI 应用程序(为 Android 设备配置)作为客户端应用程序。
我开始这样的服务:
public static IHostBuilder CreateHostBuilder(string[] args)
{
var configuration = ServiceFactory.Instance.GetConfiguration();
return Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(options =>
{
options.Listen(configuration.IPAddress, configuration.HttpPort);
options.Listen(configuration.IPAddress, configuration.HttpsPort, configure => configure.UseHttps());
});
webBuilder.UseStartup<Startup>();
});
}
服务器应用程序启动精美。
桌面客户端工作
当我启动我的 WPF 桌面应用程序时,我使用以下代码连接到服务器并运行最基本的服务功能:Ping。它是一个始终返回有效响应对象的函数,它用作测试服务器是否处于活动状态,我还可以测试一般服务调用是否有效。
_grpcChannel = GrpcChannel.ForAddress("https://127.0.0.1:5005/", new GrpcChannelOptions()
{
MaxReceiveMessageSize = 16 * 1024 * 1024,
MaxSendMessageSize = 16 * 1024 * 1024,
HttpHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
}
});
_authenticationClient = new AuthenticationClient(_grpcChannel);
_authenticationClient.Ping(new PingRequest());
手机客户端打不开
这完全符合预期。但是,当我在我的 .NET MAUI 应用程序中使用下面的代码时,它失败了。
_grpcChannel = GrpcChannel.ForAddress("http://127.0.0.1:5000/", new GrpcChannelOptions()
{
MaxReceiveMessageSize = 16 * 1024 * 1024,
MaxSendMessageSize = 16 * 1024 * 1024
});
_authenticationClient = new AuthenticationClient(_grpcChannel);
_authenticationClient.Ping(new PingRequest());
我使用 HTTP 而不是 HTTPS,因为没有有效 SSL 证书的 HTTPS 显然存在问题,例如当你在本地测试时。我读过这个here.
创建 gRPC 通道在我的 .NET MAUI 应用程序中确实有效,我还可以创建我的 AuthenticationClient 实例。但是,当我调用 Ping 服务功能时,我得到了这个。
{Grpc.Core.RpcException: Status(StatusCode="Unavailable", Detail="Error connecting to subchannel.", DebugException="System.Net.Sockets.SocketException (111): Connection refused
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|277_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
at Grpc.Net.Client.Balancer.Internal.SocketConnectivitySubchannelTransport.TryConnectAsync(ConnectContext context) in /_/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs:line 140")
at Grpc.Net.Client.Balancer.Internal.ConnectionManager.PickAsync(PickContext context, Boolean waitForReady, CancellationToken cancellationToken) in /_/src/Grpc.Net.Client/Balancer/Internal/ConnectionManager.cs:line 352
at Grpc.Net.Client.Balancer.Internal.BalancerHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /_/src/Grpc.Net.Client/Balancer/Internal/BalancerHttpHandler.cs:line 109
at Grpc.Net.Client.Internal.GrpcCall`2.<RunCall>d__73[[Engine.Server.Contracts.PingRequest, Engine.Server.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Engine.Server.Contracts.PingResponse, Engine.Server.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() in /_/src/Grpc.Net.Client/Internal/GrpcCall.cs:line 493
at Grpc.Net.Client.Internal.HttpClientCallInvoker.BlockingUnaryCall[PingRequest,PingResponse](Method`2 method, String host, CallOptions options, PingRequest request) in /_/src/Grpc.Net.Client/Internal/HttpClientCallInvoker.cs:line 116
at Grpc.Core.Interceptors.InterceptingCallInvoker.<BlockingUnaryCall>b__3_0[PingRequest,PingResponse](PingRequest req, ClientInterceptorContext`2 ctx) in /_/src/Grpc.Core.Api/Interceptors/InterceptingCallInvoker.cs:line 51
at Grpc.Core.ClientBase.ClientBaseConfiguration.ClientBaseConfigurationInterceptor.BlockingUnaryCall[PingRequest,PingResponse](PingRequest request, ClientInterceptorContext`2 context, BlockingUnaryCallContinuation`2 continuation) in /_/src/Grpc.Core.Api/ClientBase.cs:line 174
at Grpc.Core.Interceptors.InterceptingCallInvoker.BlockingUnaryCall[PingRequest,PingResponse](Method`2 method, String host, CallOptions options, PingRequest request) in /_/src/Grpc.Core.Api/Interceptors/InterceptingCallInvoker.cs:line 48
at Engine.Server.Contracts.Authentication.AuthenticationClient.Ping(PingRequest request, CallOptions options) in [a path]\obj\Debug\net6.0\AuthenticationGrpc.cs:line 316
at Engine.Server.Contracts.Authentication.AuthenticationClient.Ping(PingRequest request, Metadata headers, Nullable`1 deadline, CancellationToken cancellationToken) in [a path]\obj\Debug\net6.0\AuthenticationGrpc.cs:line 306
不幸的是,网络研究并没有透露太多,我对 .NET MAUI 开发还很陌生。非常感谢任何帮助。
10.0.2.2
是 Android Emulator 的 loopback 地址。因此,要使其在模拟器中运行,您需要使用:
_grpcChannel = GrpcChannel.ForAddress("http://10.0.2.2:5000/", new GrpcChannelOptions()
{
MaxReceiveMessageSize = 16 * 1024 * 1024,
MaxSendMessageSize = 16 * 1024 * 1024
});