You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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实例,彻底避免跨进程问题。

步骤:

  1. 给WPF项目安装以下NuGet包:

    • Microsoft.AspNetCore.Server.Kestrel
    • Grpc.AspNetCore
    • Microsoft.AspNetCore.Http.Abstractions
  2. 在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,轻量高效)

  1. 在CommonHelper项目中定义IPC消息结构:

    public class IpcRequest
    {
        public string UniqueId { get; set; }
        public string Result { get; set; }
    }
    
  2. 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();
            }
        });
    }
    
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 10:18:57