.netcore grpc的proto文件字段详解
一、.proto文件字段概述
- grpc的接口传输参数都是根据.proto文件约定的字段格式进行传输的
- grpc提供了多种类型字段;主要包括标量值类型(基础类型)、日期时间、可为null类型、字节、列表、字典、Any类型(任意类型)、Oneof等
- 字段严格规范,是一种强类型文件协议
二、案例介绍
- 标量值类型
- 日期时间
- 可为null类型
- 字节
- 列表
- 字典
- Any类型
- Oneof:一种语言特性,可以通过该特性进行对象切换处理;使用
oneof
指定可能返回 A对象或B对象 的响应消息
三、服务端定义
- 定义通用消息实体
- 根据不同的类型创建对应的案例实体
- 特殊的字段需要导入指定的包才能使用
- 定义引用字段的各个服务接口
- 内部实现逻辑,及打印展示相应的字段结果
// 1.提供公共的实体proto文件
// 2.服务引用对应的proto文件// 通用消息文件datamessages.proto
syntax = "proto3";option csharp_namespace = "GrpcProject";package grpc.serviceing;// 基础类型实体
message BaseConfig{string name = 1;double position = 2;float distance= 3 ;int32 age = 4;int64 timeSpanId = 5;uint32 uAge = 6;uint64 uTimeSpanId = 7;sint32 sAge = 8;sint64 sTimeSpanId = 9;bool flag = 10;
}// 日期类型实体 需要导入 日期namespace
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";message DateConfig{int64 id = 1;google.protobuf.Timestamp dateTimestamp = 2;google.protobuf.Duration dateDuration = 3;
}// 字节类型
message ByteConfig{int64 id = 1;bytes positionBytes = 2;
}// 可为null类型 需要导入 null的namespace
import "google/protobuf/wrappers.proto";message NullConfig{int64 id = 1;google.protobuf.BoolValue nullBool = 2;google.protobuf.DoubleValue nullDoubule = 3;google.protobuf.FloatValue nullFloat = 4;google.protobuf.Int32Value nullInt = 5;google.protobuf.Int64Value nullLong = 6;google.protobuf.UInt32Value nullUInt = 7;google.protobuf.StringValue nullString = 8;google.protobuf.BytesValue nullBytes = 9;
}// 集合类型
message ListConfig{int64 id = 1;// 数组repeated string names = 2;repeated ListDetailConfig details = 3;// 字典map<int32,string> attributes = 4;map<int32,ListDetailConfig> dicDetail = 5;
}message ListDetailConfig{string name = 1;int32 height = 2;
}// 任意类型 需要导入对应的包
import "google/protobuf/any.proto";
message AnyConfig{int32 id = 1;google.protobuf.Any anyObject = 2;
}// Oneof类型 编译器在生成消息类时处理 oneof 关键字。 使用 oneof 指定可能返回 A 或 B 或 C 的响应消息
message OneofConfig{oneof result{A oA = 1;B oB = 2;C oC = 3;}
}message A{int32 id = 1;
}message B{int32 id = 1;
}message C{int32 id =1;
}
// 接口服务定义protofield.proto文件syntax = "proto3";import "google/protobuf/empty.proto";
import "Protos/datamessages.proto";option csharp_namespace = "GrpcProject";package grpc.serviceing;service FieldRpc{// 基础字段处理rpc BaseConfigService(BaseConfig) returns (google.protobuf.Empty);// 日期字段处理rpc DateConfigService(DateConfig) returns (google.protobuf.Empty);// 字节处理rpc ByteConfigService(ByteConfig) returns (google.protobuf.Empty);// null字段处理rpc NullConfigService(NullConfig) returns (google.protobuf.Empty);// 集合类型字段处理rpc ListConfigService(ListConfig) returns (google.protobuf.Empty);// 任意类型字段处理rpc AnyConfigService(AnyConfig) returns (google.protobuf.Empty);// Oneof类型字段处理rpc OneofConfigService(OneofConfig) returns (google.protobuf.Empty);
}
// 服务实现类/// <summary>/// 字段处理服务/// </summary>public class ProtoFieldService : FieldRpc.FieldRpcBase{// 基础配置public override async Task<Empty> BaseConfigService(BaseConfig request, ServerCallContext context){await Console.Out.WriteLineAsync("\r\n--------------------------基础配置--------------------------\r\n");// 打印字段信息var properties = request.GetType().GetProperties();foreach (var property in properties){var value = property.GetValue(request);await Console.Out.WriteLineAsync($"{property.Name}:{value}");}return new Empty();}// 日期配置public override async Task<Empty> DateConfigService(DateConfig request, ServerCallContext context){await Console.Out.WriteLineAsync("\r\n--------------------------日期配置--------------------------\r\n");// timspanvar duration = request.DateDuration.ToTimeSpan();await Console.Out.WriteLineAsync($"{nameof(duration)}:{duration.TotalSeconds}");// datetimevar time = request.DateTimestamp.ToDateTime();await Console.Out.WriteLineAsync($"{nameof(time)}:{time:yyyy-MM-dd HH:mm:ss}");return new Empty();}// 字节public override async Task<Empty> ByteConfigService(ByteConfig request, ServerCallContext context){await Console.Out.WriteLineAsync("\r\n--------------------------字节配置--------------------------\r\n");var bytes = request.PositionBytes.ToByteArray();var message = Encoding.UTF8.GetString(bytes, 0, bytes.Length);await Console.Out.WriteLineAsync($"{nameof(message)}:{message}");return new Empty();}// null配置public override async Task<Empty> NullConfigService(NullConfig request, ServerCallContext context){await Console.Out.WriteLineAsync("\r\n--------------------------null配置--------------------------\r\n");// 打印字段信息var properties = request.GetType().GetProperties();foreach (var property in properties){var value = property.GetValue(request);var printValue = value == null ? "返回null值" : value;await Console.Out.WriteLineAsync($"{property.Name}:{printValue}");}return new Empty();}// 集合public override async Task<Empty> ListConfigService(ListConfig request, ServerCallContext context){await Console.Out.WriteLineAsync("\r\n--------------------------集合配置--------------------------\r\n");var id = request.Id;await Console.Out.WriteLineAsync($"主键标识:{id}\r\n");// 转换数组arrayawait Console.Out.WriteLineAsync($"打印names信息:");var names = request.Names.ToArray();foreach (var name in names){await Console.Out.WriteLineAsync(name);}// 转换listawait Console.Out.WriteLineAsync($"\r\n打印detailList信息:");var detailList = request.Details.ToList();foreach (var item in detailList){await Console.Out.WriteLineAsync($"ListDetailConfig:{nameof(item.Name)} {item.Name};{nameof(item.Height)} {item.Height}。");}// 字典await Console.Out.WriteLineAsync($"\r\n打印一般字典信息:");var dicAttributes = request.Attributes.ToDictionary(t => t.Key, t => t.Value);foreach (var attr in dicAttributes){await Console.Out.WriteLineAsync($"key:{attr.Key};value:{attr.Value}。");}await Console.Out.WriteLineAsync($"\r\n打印对象字典信息:");foreach (var item in request.DicDetail){await Console.Out.WriteLineAsync($"key:{item.Key};value:{item.Value.Name} | {item.Value.Height}。");}return new Empty();}// Anypublic override async Task<Empty> AnyConfigService(AnyConfig request, ServerCallContext context){await Console.Out.WriteLineAsync("\r\n--------------------------Any配置--------------------------\r\n");var anyObject = request.AnyObject;// 检查是否是A对象if (anyObject.Is(A.Descriptor)){var a = anyObject.Unpack<A>();if (a is not null){await Console.Out.WriteLineAsync($"A对象:{a.Id}");}}else if (anyObject.Is(B.Descriptor)){var b = anyObject.Unpack<B>();if (b is not null){await Console.Out.WriteLineAsync($"B对象:{b.Id}");}}else if (anyObject.Is(C.Descriptor)){var c = anyObject.Unpack<C>();if (c is not null){await Console.Out.WriteLineAsync($"C对象:{c.Id}");}}else{await Console.Out.WriteLineAsync("Any未解析到任何对象");}return new Empty();}// oneofpublic override async Task<Empty> OneofConfigService(OneofConfig request, ServerCallContext context){await Console.Out.WriteLineAsync("\r\n--------------------------Oneof配置--------------------------\r\n");// 检测对应的对象是否有值switch (request.ResultCase){case OneofConfig.ResultOneofCase.None:await Console.Out.WriteLineAsync("未检测到任何对象");break;case OneofConfig.ResultOneofCase.OA:await Console.Out.WriteLineAsync($"对象OA存在值:{request.OA.Id}");break;case OneofConfig.ResultOneofCase.OB:await Console.Out.WriteLineAsync($"对象OB存在值:{request.OB.Id}");break;case OneofConfig.ResultOneofCase.OC:await Console.Out.WriteLineAsync($"对象OC存在值:{request.OC.Id}");break;default:break;}return new Empty();}}
三、客户端定义
- 引用proto文件,配置为客户端类型
- 根据编译生成的函数进行传参调用
- 创建WPF测试客户端
- 各个服务接口创建对应的按钮进行调用
- 执行过程中,服务端控制台会打印对应的消息
// 基础private async void BtnBaseconfig_Click(object sender, RoutedEventArgs e){await WpfFieldClient.Show(1);MessageBox();}// 日期private async void BtnDateconfig_Click(object sender, RoutedEventArgs e){await WpfFieldClient.Show(2);MessageBox();}// 字节private async void BtnByteconfig_Click(object sender, RoutedEventArgs e){await WpfFieldClient.Show(3);MessageBox();}// nullprivate async void BtnNullconfig_Click(object sender, RoutedEventArgs e){await WpfFieldClient.Show(4);MessageBox();}// listprivate async void BtnListconfig_Click(object sender, RoutedEventArgs e){await WpfFieldClient.Show(5);MessageBox();}// anyprivate async void BtnAnyconfig_Click(object sender, RoutedEventArgs e){await WpfFieldClient.Show(6);MessageBox();}// Oneofprivate async void BtnOneofconfig_Click(object sender, RoutedEventArgs e){await WpfFieldClient.Show(7);MessageBox();}
调用的类库:
public class WpfFieldClient{/// <summary>/// 根据参数选择不同的方法执行/// </summary>/// <param name="k"></param>public static async Task Show(int k){var channel = GrpcChannel.ForAddress("https://localhost:7188");var client = new GrpcProject.FieldRpc.FieldRpcClient(channel);// 基础BaseConfig config = new BaseConfig();config.Name = "张三";config.Position = 2.33D;config.Distance = 5.48F;config.Age = 10;config.TimeSpanId = 6538590027736100;config.SAge = 1921;config.STimeSpanId = 6538590027736130;config.Flag = true;// 日期DateConfig dateConfig = new DateConfig();dateConfig.Id = 179;dateConfig.DateDuration = Duration.FromTimeSpan(TimeSpan.FromSeconds(5));// 注意这里的时间是utc时间dateConfig.DateTimestamp = Timestamp.FromDateTime(DateTime.UtcNow);// 字节ByteConfig byteConfig = new ByteConfig();byteConfig.Id = 9854564654654;byteConfig.PositionBytes = ByteString.CopyFrom(Encoding.UTF8.GetBytes("庄这人的南的很"));// nullNullConfig nullConfig = new NullConfig();nullConfig.Id = 1854564654654;nullConfig.NullBool = true;nullConfig.NullFloat = null;nullConfig.NullUInt = null;nullConfig.NullInt = 15;nullConfig.NullLong = 112345451234787;// ListConfigListConfig listConfig = new ListConfig();var attributes = new Dictionary<int, string>{[1] = "one",[2] = "two",[3] = "three",[4] = "four",[5] = "five"};listConfig.Id = 123456456;listConfig.Attributes.Add(attributes);var dicDetail = new Dictionary<int, ListDetailConfig>{[1] = new ListDetailConfig { Height = 1, Name = "one" },[2] = new ListDetailConfig { Height = 2, Name = "two" },[3] = new ListDetailConfig { Height = 3, Name = "three" },[4] = new ListDetailConfig { Height = 4, Name = "four" },[5] = new ListDetailConfig { Height = 5, Name = "five" }};listConfig.DicDetail.Add(dicDetail);listConfig.Details.Add(new ListDetailConfig { Height = 8, Name = "Eight" });var detailConfigs = new List<ListDetailConfig>{new ListDetailConfig { Height=9,Name="nine"},new ListDetailConfig{ Height=10,Name="ten"}};listConfig.Details.Add(detailConfigs);// AnyAnyConfig anyConfig = new AnyConfig();anyConfig.Id = 42564134;anyConfig.AnyObject = Any.Pack(new B { Id = 15 });// OneofOneofConfig oneofConfig = new OneofConfig();oneofConfig.OA = new A { Id = 1 };//oneofConfig.OC = new C { Id = 2 };var emptyResult = k switch{1 => await client.BaseConfigServiceAsync(config),2 => await client.DateConfigServiceAsync(dateConfig),3 => await client.ByteConfigServiceAsync(byteConfig),4 => await client.NullConfigServiceAsync(nullConfig),5 => await client.ListConfigServiceAsync(listConfig),6 => await client.AnyConfigServiceAsync(anyConfig),7 => await client.OneofConfigServiceAsync(oneofConfig),_ => new Empty()};}}
五、执行结果
服务端:
客户端:
六、源码地址
链接:https://pan.baidu.com/s/150TKY2Kgln3l_uKAsztyzw
提取码:hkb9
下一篇https://blog.csdn.net/qq_31975127/article/details/132345428
相关文章:

.netcore grpc的proto文件字段详解
一、.proto文件字段概述 grpc的接口传输参数都是根据.proto文件约定的字段格式进行传输的grpc提供了多种类型字段;主要包括标量值类型(基础类型)、日期时间、可为null类型、字节、列表、字典、Any类型(任意类型)、One…...

带你了解建堆的时间复杂度
目录 用向上调整建堆的时间复杂度 1.向上调整建堆的时间复杂度O(N*logN) 2.数学论证 3.相关代码 用向下调整建堆的时间复杂度 1.建堆的时间复杂度为O(N) 2.数学论证 3.相关代码 完结撒花✿✿ヽ(▽)ノ✿✿ 博主建议:面试的时候可能会被面试官问到建堆时间复杂度的证明过…...
人工智能原理(6)
目录 一、机器学习概述 1、学习和机器学习 2、学习系统 3、机器学习发展简史 4、机器学习分类 二、归纳学习 1、归纳学习的基本概念 2、变型空间学习 3、归纳偏置 三、决策树 1、决策树组成 2、决策树的构造算法CLS 3、ID3 4、决策树的偏置 四、基于实例的学习…...
单片机模块化编程文件创建流程
一、在工程文件夹下创建一个新的文件夹,命名为“ModulesCodesFiles”,译为“模块化代码文件”,用于存放所有模块化代码文件。 二、在“ModulesCodesFiles”文件夹下为每个模块创建一个新的文件夹,命名为模块的名称,例…...
docker image
docker image 1. 由来 docker image是Docker容器管理工具中的一个命令,用于管理和操作Docker镜像。 2. 常见五种示例命令和说明 以下是docker image的常见示例命令及其说明: 示例一:列出所有镜像 docker image ls描述:使用d…...
力扣75——单调栈
总结leetcode75中的单调栈算法题解题思路。 上一篇:力扣75——区间集合 力扣75——单调栈 1 每日温度2 股票价格跨度1 - 2 解题总结 1 每日温度 题目: 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer &…...
Webpack和Parcel详解
构建工具和打包器是在开发过程中帮助组织、优化和打包项目的工具。它们可以处理依赖管理、资源优化、代码转换等任务,从而使开发流程更高效。以下是关于构建工具和打包器的一些指导: **Webpack:** Webpack 是一个功能强大的模块打包器&#…...

linux系统服务学习(六)FTP服务学习
文章目录 FTP、NFS、SAMBA系统服务一、FTP服务概述1、FTP服务介绍2、FTP服务的客户端工具3、FTP的两种运行模式(了解)☆ 主动模式☆ 被动模式 4、搭建FTP服务(重要)5、FTP的配置文件详解(重要) 二、FTP任务…...

7.原 型
7.1原型 【例如】 另外- this指向: 构造函数和原型对象中的this都指向实例化的对象 7.2 constructor属性 每个原型对象里面都有个constructor属性( constructor构造函数) 作用:该属性指向该原型对象的构造函数 使用场景: 如果有多个对象的方法&#…...

【图像分类】理论篇(2)经典卷积神经网络 Lenet~Resenet
目录 1、卷积运算 2、经典卷积神经网络 2.1 Lenet 网络构架 代码实现 2.2 Alexnet 网络构架 代码实现 2.3 VGG VGG16网络构架 代码实现 2.4 ResNet ResNet50网络构架 代码实现 1、卷积运算 在二维卷积运算中,卷积窗口从输入张量的左上角开始ÿ…...

C++系列-内存模型
内存模型 内存模型四个区代码区全局区栈区堆区内存开辟和释放在堆区开辟数组 内存模型四个区 不同区域存放的数据生命周期是不同的,更为灵活。 代码区:存放函数体的二进制代码,操作系统管理。全局区:存放全局变量,常…...
[管理与领导-30]:IT基层管理者 - 人的管理 - 向上管理,管理好你的上司,职业发展事半功倍。什么样的上司不值得跟随?
目录 前言: 一、什么是向上管理 二、为什么要向上管理 三、如何进行向上管理 四、向上管理的注意事项 五、向上管理的忌讳 六、向上管理常犯的错 七、如何帮助上司解决他关心的问题 7.1 如何帮助上司解决他关心的问题 7.2 如何帮助上司降低压力 八、什么…...

Java进阶篇--迭代器模式
目录 同步迭代器(Synchronous Iterator): Iterator 接口 常用方法: 注意: 扩展小知识: 异步迭代器(Asynchronous Iterator): 常用的方法 注意: 总结:…...

【CAM】CAM(Class Activation Mapping)——可视化CNN的特征定位
文章目录 一、CAM(Class Activation Mapping)二、CAM技术实现2.1 网络修改2.2 微调2.2 特征提取 三、总结Reference 完整代码见Github :https://github.com/capsule2077/CAM-Visualization ,如果有用可以点个Star,谢谢! 一、CAM(C…...
Maven教程_编程入门自学教程_菜鸟教程-免费教程分享
教程简介 Maven 是一款基于 Java 平台的项目管理和整合工具,它将项目的开发和管理过程抽象成一个项目对象模型(POM)。开发人员只需要做一些简单的配置,Maven 就可以自动完成项目的编译、测试、打包、发布以及部署等工作。Maven 是…...
Gof23设计模式之模板方法模式
1.定义 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 2.结构 模板方法(Template Method)模式包含以下主要角色: 抽象类࿰…...

springBoot 配置文件 spring.resources.add-mappings 参数的作用
在Spring Boot应用中,spring.resources.add-mappings参数用于控制是否将特定路径的资源文件添加到URL路径映射中。 默认情况下,该参数的值为true,即会自动将静态资源(例如CSS、JavaScript、图片等)的URL路径添加到Spr…...

《Java极简设计模式》第03章:工厂方法模式(FactoryMethod)
作者:冰河 星球:http://m6z.cn/6aeFbs 博客:https://binghe.gitcode.host 文章汇总:https://binghe.gitcode.host/md/all/all.html 源码地址:https://github.com/binghe001/java-simple-design-patterns/tree/master/j…...

C++11并发与多线程笔记(11) std::atomic续谈、std::async深入谈
C11并发与多线程笔记(11) std::atomic续谈、std::async深入谈 1、std::atomic续谈2、std::async深入理解2.1 std::async参数详述2.2 std::async和std::thread()区别:2.3 async不确定性问题的解决 1、std::atomic续谈 #include <iostream&…...

React快速入门
最近需要学到react,这里进行一个快速的入门,参考react官网 1.创建和嵌套组件 react的组件封装是个思想,我这里快速演示代码,自己本身也不太熟悉。 代码的路径是src底下的App.js function MyButton() {return (<button>I…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...