WPF 桌面应用程序中的 gRPC 服务器?

问题描述 投票:0回答:2

我目前正在使用 gRPC,到目前为止已经创建了一个简单的 C# hello world 演示,使用 Visual Studio

ASP.Net Core gRPC Service
项目作为服务器,以及客户端控制台应用程序。

接下来我想做的是让 gRPC 服务器在 .Net 6 WPF 桌面应用程序(称为“AppA”)中运行,从而允许另一个桌面应用程序(“AppB”)向 AppA 发出信息请求。这可能吗?

通常我会使用 WCF 来实现此目的,但由于 CoreWCF 的不成熟,我被警告不要使用它。

.net asp.net-core grpc
2个回答
5
投票

我找到了一种在 WPF 桌面应用程序中托管 gRPC 服务的方法。

该项目需要引用“Grpc.AspNetCore”包(没有“proto”东西,稍后你会明白为什么)。

然后是启动 Web 应用程序的代码。出于演示应用程序的目的,我在 MainWindow.xaml.cs 中实现了此功能:

private WebApplication? _app;

public MainWindow()
{
    InitializeComponent();
    Task.Run(() => StartServer());
}

private void StartServer()
{
    var builder = WebApplication.CreateBuilder();

    // Despite adding a "launchSettings.json" file to the project, I couldn't find a way 
    // for the builder to pick it up, so had to configure the URLs here:
    builder.WebHost.UseUrls("http://*:5219", "https://*:7219");

    builder.Services.AddGrpc();

    _app = builder.Build();
    _app.MapGrpcService<TestService>();
    _app.Run();
}

private void MainWindow_OnClosing(object? sender, CancelEventArgs e)
{
    _app?.StopAsync();
}

对 _app.Run() 的调用会阻塞(直到 Web 应用程序停止),这就是为什么我在 b/g 线程上调用 StartServer() 的原因。

我发现一篇文章说proto编译器在WPF项目中不能正常工作。尽管它正在生成类,但构建错误表明无法找到这些类。 解决方案是将“protos”内容和服务类添加到类库中,然后从 WPF“服务器”引用它。类库项目需要引用以下包:

  • Google.Protobuf
  • Grpc.AspNetCore
  • Grpc.工具

0
投票

我们的 WPF .NET 6 应用程序是使用 Grpc.Core NUGET 包的 gRPC 服务器。我还没有迁移到新的 Grpc.NET 实现。当我这样做时,希望它不会强制使用 Asp.NET 而不是 WPF。以下是详细信息。希望它能带您到达您需要去的地方!

创建服务器定义后,以下是我们的 WPF 应用程序中创建服务器的方法:

        private void CreateServer()
    {
        string[] ipAddresses = GetLocalIPAddresses();

        // insecure
        m_server = new Server
        {
            Services =
            {
                GrpcServer.BindService(this).Intercept(new IpAddressAuthenticator())
            }
        };

        // Add the IP addresses
        for (int i = 0; i < ipAddresses.Length; i++)
        {
            m_server.Ports.Add(new ServerPort(ipAddresses[i], remPort, ServerCredentials.Insecure));
        }

    }

这是 IpAddressAuthenticator 代码:

public class IpAddressAuthenticator : Interceptor
{
    private readonly HashSet<string> m_authenticatedIps = new HashSet<string>()
    {
        "127.0.0.1",
        "::1"
    };

    private void VerifyPeer(ServerCallContext context)
    {
        context.Status = new Status(StatusCode.OK, $"Authenticated peer: {context.Peer}");
    }

    private bool TryTakeIpAddress(string peer, out string ipAddress)
    {
        // ex.
        // "ipv4:127.0.0.1:12345"
        // "ipv6:[::1]:12345"

        var ipv4Match = Regex.Match(peer, @"^ipv4:(.+):");
        if (ipv4Match.Success)
        {
            ipAddress = ipv4Match.Groups[1].Value;
            return true;
        }

        var ipv6Match = Regex.Match(peer, @"^ipv6:\[(.+)\]");
        if (ipv6Match.Success)
        {
            ipAddress = ipv6Match.Groups[1].Value;
            return true;
        }

        ipAddress = "";
        return false;
    }

    public override Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
    {
        VerifyPeer(context);
        return base.ClientStreamingServerHandler(requestStream, context, continuation);
    }

    public override Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
    {
        VerifyPeer(context);
        return base.DuplexStreamingServerHandler(requestStream, responseStream, context, continuation);
    }

    public override Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
    {
        VerifyPeer(context);
        return base.ServerStreamingServerHandler(request, responseStream, context, continuation);
    }

    public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
    {
        VerifyPeer(context);
        return base.UnaryServerHandler(request, context, continuation);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.