如何实现gRPC Server与WPF应用的跨进程对象更新?
问题根源
你遇到的核心问题是跨进程的单例类不共享实例:WPF应用和通过Process.Start()启动的gRPC Server是两个独立的Windows进程,各自拥有独立的内存空间。WPF进程中订阅了SelectItemByGuid事件的MyManager.Instance,和gRPC Server进程里的MyManager.Instance是完全不同的对象,因此gRPC触发事件时,WPF端的订阅方法根本不会收到通知。
解决方案
方案1:将gRPC Server嵌入WPF进程(推荐)
把gRPC Server直接在WPF进程内启动,让两者共享同一个MyManager实例,彻底避免跨进程问题。
步骤:
给WPF项目安装以下NuGet包:
Microsoft.AspNetCore.Server.KestrelGrpc.AspNetCoreMicrosoft.AspNetCore.Http.Abstractions
在WPF的ViewModel或窗口后台代码中实现gRPC Server启动逻辑:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.DependencyInjection; using System.Threading.Tasks; private IWebHost _grpcHost; // 启动gRPC服务的方法(比如按钮点击事件) public void StartEmbeddedGrpcServer() { // 先订阅事件(确保同一个实例) MyManager.Instance.SelectItemByGuid += InstanceOnSelectItemByGuid; // 配置并启动Kestrel服务器 _grpcHost = new WebHostBuilder() .UseKestrel(options => { // 监听HTTP2端口 options.ListenAnyIP(5116, o => o.Protocols = HttpProtocols.Http2); options.ListenAnyIP(7224, o => { o.Protocols = HttpProtocols.Http2; // 如需HTTPS,在此配置证书 // o.UseHttps("your-cert.pfx", "cert-password"); }); }) .ConfigureServices(services => { services.AddGrpc(); }) .Configure(app => { app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGrpcService<GreeterService>(); }); }) .Build(); // 异步启动服务器,避免阻塞WPF UI线程 _ = _grpcHost.StartAsync(); } // WPF窗口关闭时停止gRPC服务 private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { _grpcHost?.StopAsync().Wait(); }
这样gRPC Server和WPF运行在同一个进程内,MyManager的单例是同一个对象,gRPC调用时WPF的事件订阅方法会正常触发。
方案2:跨进程通信(IPC)(需保持gRPC独立进程时使用)
如果必须让gRPC Server作为独立进程运行,需要在gRPC和WPF之间建立IPC通道,实现进程间消息传递。
方式A:命名管道(Named Pipes,轻量高效)
在CommonHelper项目中定义IPC消息结构:
public class IpcRequest { public string UniqueId { get; set; } public string Result { get; set; } }WPF端作为命名管道服务器,监听请求:
using System.IO.Pipes; using System.Runtime.Serialization.Json; using System.Threading.Tasks; private NamedPipeServerStream _pipeServer; public void StartPipeServer() { _pipeServer = new NamedPipeServerStream("WpfGrpcIpc", PipeDirection.InOut, 1, PipeTransmissionMode.Message); // 异步监听管道连接 _ = Task.Run(async () => { while (true) { await _pipeServer.WaitForConnectionAsync(); var serializer = new DataContractJsonSerializer(typeof(IpcRequest)); // 读取gRPC发来的请求 var request = (IpcRequest)serializer.ReadObject(_pipeServer); // 执行WPF端的业务逻辑 request.Result = InstanceOnSelectItemByGuid(request.UniqueId); // 返回结果给gRPC serializer.WriteObject(_pipeServer, request); _pipeServer.WaitForPipeDrain(); _pipeServer.Disconnect(); } }); }gRPC Server端作为命名管道客户端,发送请求并获取结果:
修改MyManager的SelectItem方法:public string SelectItem(string deviceUniqueId) { using (var pipeClient = new NamedPipeClientStream(".", "WpfGrpcIpc", PipeDirection.InOut, PipeOptions.Asynchronous)) { pipeClient.Connect(5000); // 超时5秒 var serializer = new DataContractJsonSerializer(typeof(IpcRequest)); // 发送请求 var request = new IpcRequest { UniqueId = deviceUniqueId }; serializer.WriteObject(pipeClient, request); pipeClient.WaitForPipeDrain(); // 读取返回结果 var response = (IpcRequest)serializer.ReadObject(pipeClient); return response.Result; } }
方式B:TCP Socket
和命名管道逻辑类似,通过TCP建立WPF(服务器)和gRPC(客户端)的连接,使用JSON或Protobuf序列化消息进行通信,适合跨机器场景。
内容的提问来源于stack exchange,提问作者MURALI MAHENDRA BANALA
相关产品推荐
相关产品推荐

