尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

WPF/WinForms 客户端通过 gRPC 与后端通信:从 Proto 契约到流式调用的完整指南

WPF/WinForms 客户端通过 gRPC 与后端通信:从 Proto 契约到流式调用的完整指南 WPF/WinForms 客户端通过 gRPC 与后端通信从 Proto 契约到流式调用的完整指南引言做过桌面客户端的同学以前和后端通信基本都是 HTTP JSONREST。但当接口变多、字段变多、对性能有要求时REST 的痛点就来了字段冗余、没有强类型契约、序列化开销大。gRPC解决了这些问题用 Protobuf 做序列化体积小、快用.proto文件做强类型契约前后端字段不会对不上还天然支持双向流。本文面向 WPF/WinForms 开发者讲清客户端用 gRPC 通信需要掌握的全部知识点。环境.NET 6/8NuGet 包Grpc.Net.ClientGoogle.ProtobufGrpc.Tools。一、什么是 gRPC 和 Proto 契约gRPC 是 Google 开源的 RPC 框架基于 HTTP/2默认用Protobuf做序列化。对比 REST维度REST (HTTP JSON)gRPC契约无强类型靠文档约定.proto强类型契约序列化JSON 文本体积大Protobuf 二进制体积小、快通信模式基本是一问一答支持单向、服务端流、客户端流、双向流传输HTTP/1.1HTTP/2多路复用核心是.proto文件——它同时定义了有哪些服务和消息长什么样syntax proto3; package greet; // 定义服务 service Greeter { // 一元调用 rpc SayHello (HelloRequest) returns (HelloReply); // 服务端流式 rpc SayHelloStream (HelloRequest) returns (stream HelloReply); } // 定义消息 message HelloRequest { string name 1; } message HelloReply { string message 1; }二、生成强类型客户端.proto文件要通过Grpc.Tools在编译时自动生成 C# 客户端代码。2.1 引入包与配置在客户端项目的.csproj里ItemGroupPackageReferenceIncludeGrpc.Net.ClientVersion2.*/PackageReferenceIncludeGoogle.ProtobufVersion3.*/PackageReferenceIncludeGrpc.ToolsVersion2.*PrivateAssetsAll//ItemGroupItemGroup!-- 指定 proto 文件GrpcServicesClient 表示生成客户端 --ProtobufIncludeProtos\greet.protoGrpcServicesClient//ItemGroup编译后会生成一个Greeter.GreeterClient类直接new就能用。关键点proto 文件是前后端共享的契约源最好放在公共仓库/子模块里由后端维护客户端引用同一份避免字段对不上。三、建立连接GrpcChannel3.1 创建 Channel 和 ClientusingGrpc.Net.Client;usingGrpc.Core;// 创建通道Channel 是重资源要复用不要每次调用都新建usingvarchannelGrpcChannel.ForAddress(https://localhost:5001);// 创建客户端varclientnewGreeter.GreeterClient(channel);// 一元调用varreplyawaitclient.SayHelloAsync(newHelloRequest{Name张三});Console.WriteLine(reply.Message);3.2 Channel 的生命周期重要GrpcChannel底层是一个HttpClient连接复用是 gRPC 性能的关键不要每次调用都new GrpcChannel否则连接池失效、性能骤降。在应用生命周期内全局复用一个 Channel用单例或依赖注入管理。程序退出前正确Dispose。用 DI 管理最优雅需引用Grpc.Net.ClientFactory// 程序启动时注册.NET 6 的 Host 里builder.Services.AddGrpcClientGreeter.GreeterClient(o{o.AddressnewUri(https://localhost:5001);});之后在窗体里直接注入Greeter.GreeterClient使用即可。四、四种通信模式gRPC 支持四种调用模式这是它比 REST 强的地方。4.1 一元调用Unary一问一答最常见的场景上面已演示。4.2 服务端流Server Streaming一问多答适合实时推送比如日志流、行情推送、大文件分块下载。usingvarcallclient.SayHelloStream(newHelloRequest{Name张三});// 逐条读取服务端推送的消息awaitforeach(varreplyincall.ResponseStream.ReadAllAsync()){Console.WriteLine(reply.Message);// 想中途取消可以 break}4.3 客户端流Client Streaming多问一答适合批量上传比如批量导入数据、上传文件。usingvarcallclient.Upload();// 逐条写入foreach(varitemindataList){awaitcall.RequestStream.WriteAsync(item);}// 通知服务端发送完毕然后接收最终响应awaitcall.RequestStream.CompleteAsync();varresponseawaitcall.ResponseAsync;4.4 双向流Bidirectional Streaming边发边收适合聊天、实时协作等复杂交互两端都可随时发和收。usingvarcallclient.Chat();// 一个任务负责收varreadTaskTask.Run(async(){awaitforeach(varmsgincall.ResponseStream.ReadAllAsync())Console.WriteLine(收到: msg.Text);});// 一个任务负责发foreach(vartextinmessagesToSend){awaitcall.RequestStream.WriteAsync(newChatMsg{Texttext});}awaitcall.RequestStream.CompleteAsync();awaitreadTask;五、认证、超时与取消生产环境三件套缺一不可。5.1 认证传 Token用Metadata携带认证信息如 JWTvarheadersnewMetadata{{Authorization,Bearer accessToken}};varreplyawaitclient.SayHelloAsync(newHelloRequest{Name张三},headers);5.2 超时与取消Deadline CancellationTokengRPC 默认没有超时网络抖动会让调用一直挂起必须设置超时// 方式一CancellationTokenSource 定时取消usingvarctsnewCancellationTokenSource(TimeSpan.FromSeconds(5));varreplyawaitclient.SayHelloAsync(newHelloRequest{Name张三},cancellationToken:cts.Token);// 方式二deadline绝对时间点varreply2awaitclient.SayHelloAsync(newHelloRequest{Name张三},deadline:DateTime.UtcNow.AddSeconds(5));5.3 错误处理gRPC 异常是RpcException通过StatusCode区分try{varreplyawaitclient.SayHelloAsync(req);}catch(RpcExceptionex)when(ex.StatusCodeStatusCode.DeadlineExceeded){MessageBox.Show(请求超时请重试);}catch(RpcExceptionex)when(ex.StatusCodeStatusCode.Unauthenticated){MessageBox.Show(登录已过期);}六、进阶拦截器与重试拦截器Interceptor可以统一处理日志、注入 Token、统计耗时避免在每个调用点重复写publicclassLoggingInterceptor:Interceptor{publicoverrideAsyncUnaryCallTResponseAsyncUnaryCallTRequest,TResponse(TRequestrequest,ClientInterceptorContextTRequest,TResponsecontext,AsyncUnaryCallContinuationTRequest,TResponsecontinuation){varcallcontinuation(request,context);// 拿到响应后记录日志vartaskcall.ResponseAsync.ContinueWith(t{Log.Info(${context.Method}调用完成);});returncall;}}// 使用拦截器varinvokerchannel.Intercept(newLoggingInterceptor());varclientnewGreeter.GreeterClient(invoker);七、与 WPF/WinForms 的 UI 结合gRPC 调用是异步的桌面端的关键是别卡 UI 线程await 后安全更新界面。// WinFormsasync void 事件处理器privateasyncvoidbtnCall_Click(objectsender,EventArgse){btnCall.Enabledfalse;// 防重复点击try{varreplyawait_client.SayHelloAsync(newHelloRequest{NametextBox1.Text},deadline:DateTime.UtcNow.AddSeconds(5));// await 之后自动回到 UI 线程可直接更新控件label1.Textreply.Message;}catch(RpcExceptionex){MessageBox.Show(调用失败ex.StatusCode);}finally{btnCall.Enabledtrue;}}要点用async/awaitawait之后天然回到 UI 线程不需要InvokeWPF 的SynchronizationContext会处理好。服务端流式推送的await foreach里更新 UI 同样安全因为每次迭代都回到 UI 上下文。页面/窗体关闭时记得CancellationTokenSource取消进行中的流避免资源泄漏。总结WPF/WinForms 客户端用 gRPC 通信掌握这 7 点就够用了用.proto文件做强类型契约前后端共享同一份。Grpc.Tools编译时自动生成客户端。GrpcChannel是重资源全局复用用 DI 管理生命周期。按场景选四种通信模式一元、服务端流、客户端流、双向流。必须设超时/取消用Metadata传 Token 认证RpcException做错误处理。用拦截器统一处理日志、Token 注入。结合桌面 UI 用async/awaitawait后安全更新界面退出前取消流。gRPC Protobuf 带来的强类型、高性能、流式能力会让你的桌面客户端和后端协作更顺畅。如果你还在纠结REST 还是 gRPC下一篇我可以专门写两者的选型对比与迁移实践。本文为原创转载注明出处。觉得有用就点赞、收藏、关注感谢支持
返回列表