基于 .NET 8.0 gRPC通讯架构设计讲解,客户端+服务端
目录
1.简要说明
2.服务端设计
2.1 服务端创建
2.2 服务端设计
2.3 服务端业务模块
3.客户端设计-控制台
4.客户端设计-Avalonia桌面程序
5.客户端设计-MAUI安卓端程序
1.简要说明
gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统
项目下载地址:https://download.csdn.net/download/rotion135/90342675
整体架构设计图

解决方案预览

2.服务端设计
2.1 服务端创建
新建项目,搜索grpc 选择下图中的项目,创建;
框架最低版本支持.NET 8.0

2.2 服务端设计
先说下几个重要的文件:
launchSettings.json 部署路径等先关信息的配置文件

appsettings.json 项目设置相关配置文件
手动添加:
"Microsoft.AspNetCore.Hosting": "Information","Microsoft.AspNetCore.Routing.EndpointMiddleware": "Information",

greet.proto 通讯交互的模型设计,以及命名空间
收发消息的接口定义等,添加完成后记得保存,重新生成一下

服务类定义,还有收发消息方法重写
寻找对应的服务以及调用的方法,用的反射的机制
参数传过来 ServerName 方法Method 以及入参 Args
从容器中寻找服务,获取到实例后,调用Method,最后返回结果

public class GreeterService : Greeter.GreeterBase{private readonly ILogger<GreeterService> _logger;public GreeterService(ILogger<GreeterService> logger){_logger = logger;}public override Task<MessageResult> SendMessage(LSRequest request, ServerCallContext context){return GetResponse(request);}private async Task<MessageResult> GetResponse(LSRequest request){return await Task.Run(() =>{ResponseModel response = new ResponseModel();try{SendModel send = JsonConvert.DeserializeObject<SendModel>(request.Json);if (send == null){response.IsSuccess = false;response.Message = "Request cannot be null";}else{if (string.IsNullOrEmpty(send.ServerName) || string.IsNullOrEmpty(send.Method)){response.IsSuccess = false;response.Message = "ServerName or Method cannot be null";}else{response.RequestID = send.RequestID;// 根据服务名称,寻找对应的服务var service = BusinessModules.IocContainer.Get<IService>(send.ServerName);if (service != null){// 使用反射调用方法MethodInfo methodInfo = null;if (send.Args != null && send.Args.Length > 0){methodInfo = service.GetType().GetMethod(send.Method, send.Args.Select(arg => arg.GetType()).ToArray());}else{methodInfo = service.GetType().GetMethod(send.Method, types: new List<Type>().ToArray());}if (methodInfo != null){try{var res = methodInfo.Invoke(service, send.Args); // 执行方法response.IsSuccess = true;response.Content = JsonConvert.SerializeObject(res);}catch (Exception ex){LogOperate.Error("Method invocation failed", ex);response.IsSuccess = false;response.Message = ex.Message;}}else{response.IsSuccess = false;response.Message = "Method not found";}}else{response.IsSuccess = false;response.Message = "Server not found";}}}}catch (Exception ex){LogOperate.Error("GetResponse 发生异常", ex);response.IsSuccess = false;response.Message = ex.Message;}return new MessageResult(){Json = JsonConvert.SerializeObject(response)};});}}
在程序运行时,将服务注入

一些业务相关的服务启动,用的BusinessModules来管理,下面会介绍。
2.3 服务端业务模块
业务模块,用了我自己写的IOC容器来管理
定义服务,继承IService

业务模块启动:
/// <summary>/// 模块启动/// </summary>public static void OnStart(){try {IEnumerable<Type> types = GetService();if (types != null && types.Count() > 0){foreach (Type type in types){string serviceName = type.Name;// 获取 ServiceNameAttribute 特性var attribute = type.GetCustomAttribute<ServiceNameAttribute>();if (attribute != null) {serviceName = attribute.Name;}//注册平台 基于IService的服务平台_iocBuilder.RegisterType(type,serviceName,LifeTimeType.Singleton);}}//创建容器IocContainer = _iocBuilder.Build();//获取所有注册的服务,基于IService的实现//然后调用服务的启动方法var services = IocContainer.GetAllService();foreach (var service in services){try{service.OnStart();}catch (Exception ex){LogOperate.Start($"启动容器中的服务发生异常,\r\n" + ex.ToString());}}}catch(Exception ex){LogOperate.Error("BusinessModules-OnStart", ex);}}
业务模块结束:
/// <summary>/// 模块结束/// </summary>public static void OnStop() {try{var services = IocContainer.GetAllService();foreach (var service in services){try{service.OnStop();}catch (Exception ex){LogOperate.Start($"停止容器中的服务发生异常,\r\n" + ex.ToString());}}}catch (Exception ex){LogOperate.Error("BusinessModules-OnStop", ex);}}
3.客户端设计-控制台
客户端设计可以多种方式,项目初始化时,需要Nuget引用下面三个包:
Google.Protobuf
Grpc.Net.Client
Grpc.Tools

添加 Protos 文件夹,添加文件greet.proto
除了命名空间修改为当前项目的之外,其余的与服务中的文件一致

运行时,创建链接,调用服务中的方法
using var channle = GrpcChannel.ForAddress("http://127.0.0.1:5237");var client = new Greeter.GreeterClient(channle);
SendModel send = new SendModel();
send.RequestID = Guid.NewGuid().ToString();
send.ServerName = "Device";
send.Method = "GetDeviceInfo";
//send.Args = new object[1];
//send.Args[0] = "1231";
var replay = await client.SendMessageAsync(new LSRequest() { Json = JsonConvert.SerializeObject(send) });
Console.WriteLine("Response:" + replay.Json);
Console.ReadKey();
4.客户端设计-Avalonia桌面程序
Avalonia 创建项目
同样需要添加三个包

同样需要添加 Protos 文件夹,添加文件greet.proto
除了命名空间修改为当前项目的之外,其余的与服务中的文件一致

客户端的设计我在这里就不多说了,可以看我的其他文章,或者下载源码来查看
这里边封装了一个gRPC的客户端类
public class GRPC_Control{private string url;private Greeter.GreeterClient client;private GrpcChannel channle;public GRPC_Control(string _url){url = _url;}public BaseResult Connect(){//"http://localhost:5237"channle = GrpcChannel.ForAddress(url);client = new Greeter.GreeterClient(channle);return BaseResult.Successed;}public BaseResult SendMessage(string service, string method, object[] args = null){try{SendModel send = new SendModel();send.RequestID = Guid.NewGuid().ToString();send.ServerName = service;send.Method = method;send.Args = args;var replay = client.SendMessage(new LSRequest() { Json = JsonConvert.SerializeObject(send) });ResponseModel response = JsonConvert.DeserializeObject<ResponseModel>(replay.Json);if (response.IsSuccess){return JsonConvert.DeserializeObject<BaseResult>(response.Content);}else{return new BaseResult(false, response.Message);}}catch (Exception ex){LogOperate.Error("SendMessage", ex);return new BaseResult(false, ex.Message);}}public async Task<BaseResult> SendMessageAsync(string service, string method, object[] args = null){return await Task.Run(async () =>{try{SendModel send = new SendModel();send.RequestID = Guid.NewGuid().ToString();send.ServerName = service;send.Method = method;send.Args = args;var replay = await client.SendMessageAsync(new LSRequest() { Json = JsonConvert.SerializeObject(send) });ResponseModel response = JsonConvert.DeserializeObject<ResponseModel>(replay.Json);if (response.IsSuccess){return JsonConvert.DeserializeObject<BaseResult>(response.Content);}else{return new BaseResult(false, response.Message);}}catch (Exception ex){LogOperate.Error("SendMessageAsync", ex);return new BaseResult(false, ex.Message);}});}}
调用方式:
case "Connect":if (gRPC == null){gRPC = new GRPC_Control(Url);gRPC.Connect();}VM_MainWindow.Instance.Popup("连接成功");break;case "Send":if (gRPC != null){var res= gRPC.SendMessage(Service, Method);Respone=JsonConvert.SerializeObject(res);}break;
5.客户端设计-MAUI安卓端程序
创建MAUI 项目,MAUI具体的使用可以参考官方文档,这里边就不展开说了
同样也是需要引用三个包

同样需要添加 Protos 文件夹,添加文件greet.proto
除了命名空间修改为当前项目的之外,其余的与服务中的文件一致

封装的gRPC客户端类与Avalonia的一致
如果对此架构感兴趣,欢迎下载源码参考参考,如有更好的建议,欢迎评论区提出
相关文章:
基于 .NET 8.0 gRPC通讯架构设计讲解,客户端+服务端
目录 1.简要说明 2.服务端设计 2.1 服务端创建 2.2 服务端设计 2.3 服务端业务模块 3.客户端设计-控制台 4.客户端设计-Avalonia桌面程序 5.客户端设计-MAUI安卓端程序 1.简要说明 gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用…...
6.Centos7上部署flask+SQLAlchemy+python+达梦数据库
情况说明 前面已经介绍了window上使用pycharm工具开发项目时,window版的python连接达梦数据库需要的第三方包。 这篇文章讲述,centos7上的python版本连接达梦数据库需要的第三方包。 之前是在windows上安装达梦数据库的客户端,将驱动包安装到windows版本的python中。(开…...
【C语言系列】深入理解指针(5)
深入理解指针(5) 一、sizeof和strlen的对比1.1sizeof1.2strlen1.3sizeof和strlen的对比 二、数组和指针笔试题解析2.1 一维数组2.2 字符数组2.2.1代码1:2.2.2代码2:2.2.3代码3:2.2.4代码4:2.2.5代码5&#…...
mysql自连接 处理层次结构数据
MySQL 的自连接(Self Join)是一种特殊的连接方式,它允许一个表与自身进行连接。自连接通常用于处理具有层次结构或递归关系的数据,或者当同一张表中的数据需要相互关联时。以下是几种常见的场景,说明何时应该使用自连接…...
##__VA_ARGS__有什么作用
##__VA_ARGS__ 是 C/C 中宏定义(Macro)的一种特殊用法,主要用于可变参数宏(Variadic Macros)的场景,解决当可变参数为空时可能导致的语法错误问题。以下是详细解释: 核心作用 消除空参数时的多余…...
鸿蒙 router.back()返回不到上个页面
1. 检查页面栈(Page Stack) 鸿蒙的路由基于页面栈管理,确保上一个页面存在且未被销毁。 使用 router.getLength() 检查当前页面栈长度: console.log(当前页面栈长度: ${router.getLength()}); 如果结果为 1,说明没有上…...
深度学习模型蒸馏技术的发展与应用
随着人工智能技术的快速发展,大型语言模型和深度学习模型在各个领域展现出惊人的能力。然而,这些模型的规模和复杂度也带来了显著的部署挑战。模型蒸馏技术作为一种优化解决方案,正在成为连接学术研究和产业应用的重要桥梁。本文将深入探讨模…...
STM32G0B1 ADC DMA normal
目标 ADC 5个通道,希望每1秒采集一遍; CUBEMX 配置 添加代码 #define ADC1_CHANNEL_CNT 5 //采样通道数 #define ADC1_CHANNEL_FRE 3 //单个通道采样次数,用来取平均值 uint16_t adc1_val_buf[ADC1_CHANNEL_CNT*ADC1_CHANNEL_FRE]; //传递…...
<tauri><rust><GUI>基于rust和tauri,在已有的前端框架上手动集成tauri示例
前言 本文是基于rust和tauri,由于tauri是前、后端结合的GUI框架,既可以直接生成包含前端代码的文件,也可以在已有的前端项目上集成tauri框架,将前端页面化为桌面GUI。 环境配置 系统:windows 10 平台:visu…...
模型 冗余系统(系统科学)
系列文章分享模型,了解更多👉 模型_思维模型目录。为防故障、保运行的备份机制。 1 冗余系统的应用 1.1 冗余系统在企业管理中的应用-金融行业信息安全的二倍冗余技术 在金融行业,信息安全是保障业务连续性和客户资产安全的关键。随着数字化…...
Deepseek部署的模型参数要求
DeepSeek 模型部署硬件要求 模型名称参数量显存需求(推理)显存需求(微调)CPU 配置内存要求硬盘空间适用场景DeepSeek-R1-1.5B1.5B4GB8GB最低 4 核(推荐多核)8GB3GB低资源设备部署,如树莓派、旧…...
AI-学习路线图-PyTorch-我是土堆
1 需求 PyTorch深度学习快速入门教程(绝对通俗易懂!)【小土堆】_哔哩哔哩_bilibili PyTorch 深度学习快速入门教程 配套资源 链接 视频教程 https://www.bilibili.com/video/BV1hE411t7RN/ 文字教程 https://blog.csdn.net/xiaotudui…...
[LeetCode]day17 349.两个数组的交集
https://leetcode.cn/problems/intersection-of-two-arrays/description/ 题目描述 给定两个数组 nums1 和 nums2 ,返回它们的交集。 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序 。 示例 1: 输入:nums1 [1,2,2,1…...
axios 发起 post请求 json 需要传入数据格式
• 1. axios 发起 post请求 json 传入数据格式 • 2. axios get请求 1. axios 发起 post请求 json 传入数据格式 使用 axios 发起 POST 请求并以 JSON 格式传递数据是前端开发中常见的操作。 下面是一个简单的示例,展示如何使用 axios 向服务器发送包含 JSON 数…...
linux交叉编译paho-mqtt-c
下载源代码: https://github.com/eclipse-paho/paho.mqtt.c.git 编译: 如果mqtt不需要SSL安全认证,可以直接执行(注意把编译工具链路径改成自己的) cd paho.mqtt.c-1.3.13/ mkdir install # 创建安装目录 mkdir…...
feign Api接口中注解问题:not annotated with HTTP method type (ex. GET, POST)
Bug Description 在调用Feign api时,出现如下异常: java.lang.IllegalStateException: Method PayFeignSentinelApi#getPayByOrderNo(String) not annotated with HTTPReproduciton Steps 1.启动nacos-pay-provider服务,并启动nacos-pay-c…...
安装指定版本的pnpm
要安装指定版本的 pnpm,可以使用以下方法: 方法 1: 使用 pnpm 安装指定版本 你可以通过 pnpm 的 add 命令来安装指定版本: pnpm add -g pnpm<版本号>例如,安装 pnpm 的 7.0.0 版本: pnpm add -g pnpm7.0.0方法…...
【系统设计】Spring、SpringMVC 与 Spring Boot 技术选型指南:人群、场景与实战建议
在 Java 开发领域,Spring 生态的技术选型直接影响项目的开发效率、维护成本和长期扩展性。然而,面对 Spring、SpringMVC 和 Spring Boot 这三个紧密关联的框架,开发者常常陷入纠结:该从何入手?如何根据团队能力和业务需…...
常用数据结构之String字符串
字符串 在Java编程语言中,字符可以使用基本数据类型char来保存,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。 操作字符串常用的有三种类:String、StringBuilder、StringBuffer 接下来看看这三类常见用…...
深入Linux系列之进程地址空间
深入Linux系列之进程地址空间 1.引入 那么在之前的学习中,我们知道我们创建一个子进程的话,我们可以在代码层面调用fork函数来创建我们的子进程,那么fork函数的返回值根据我们当前所处进程的上下文是返回不同的值,它在父进程中返…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
