Protobuf 消息
消息定义中的每个字段都有一个唯一的编号。 消息序列化为 Protobuf 时,字段编号用于标识字段。 序列化一个小编号比序列化整个字段名称要快。
标量值类型
Protobuf 类型 | C# 类型 |
---|---|
double | double |
float | float |
int32 | int |
int64 | long |
uint32 | uint |
uint64 | ulong |
sint32 | int |
sint64 | long |
fixed32 | uint |
fixed64 | ulong |
sfixed32 | int |
sfixed64 | long |
bool | bool |
string | string |
bytes | ByteString |
标量值始终具有默认值,并且该默认值不能设置为 null。 此约束包括 string 和 ByteString,它们都属于 C# 类。 string 默认为空字符串值,ByteString 默认为空字节值。 尝试将它们设置为 null 会引发错误。
对于需要显式 null 的值,请将 wrappers.proto 导入到 .proto 文件中,如以下代码所示:
syntax = "proto3"
import "google/protobuf/wrappers.proto"
message Person {
// ...
google.protobuf.Int32Value age = 5;
}
wrappers.proto 类型不会在生成的属性中公开。 Protobuf 会自动将它们映射到 C# 消息中相应的可为 null 的 .NET 类型。 例如,google.protobuf.Int32Value 字段生成 int? 属性。 引用类型属性(如 string 和 ByteString )保持不变,但可以向它们分配 null,这不会引发错误。
C# 类型 | 已知类型包装器 |
---|---|
bool? | google.protobuf.BoolValue |
double? | google.protobuf.DoubleValue |
float? | google.protobuf.FloatValue |
int? | google.protobuf.Int32Value |
long? | google.protobuf.Int64Value |
uint? | google.protobuf.UInt32Value |
ulong? | google.protobuf.UInt64Value |
string | google.protobuf.StringValue |
ByteString | google.protobuf.BytesValue |
日期和时间
本机标量类型不提供与 .NET 的 DateTimeOffset、DateTime 和 TimeSpan 等效的日期和时间值。 可使用 Protobuf 的一些“已知类型”扩展来指定这些类型。
.NET 类型 | Protobuf 已知类型 |
---|---|
DateTimeOffset | google.protobuf.Timestamp |
DateTime | google.protobuf.Timestamp |
TimeSpan | google.protobuf.Duration |
列表
Protobuf 中,在字段上使用 repeated 前缀关键字指定列表
字典
.NET IDictionary<TKey,TValue> 类型在 Protobuf 中使用 map<key_type, value_type> 表示
无结构的条件消息
Protobuf 是一种协定优先的消息传递格式。 构建应用时,必须在 .proto 文件中指定应用的消息,包括其字段和类型。 Protobuf 的协定优先设计非常适合强制执行消息内容,但可能会限制不需要严格协定的情况:
- 包含未知有效负载的消息。 例如,具有可以包含任何消息的字段的消息。
- 条件消息。 例如,从 gRPC 服务返回的消息可能是成功结果或错误结果。
- 动态值。 例如,具有包含非结构化值集合的字段的消息,类似于 JSON。
Protobuf 提供语言功能和类型来支持这些情况。
任意
import “google/protobuf/any.proto”;
利用 Any 类型,可以将消息作为嵌入类型使用,而无需 .proto 定义。 若要使用 Any 类型,请导入 any.proto。
Oneof
oneof 字段是一种语言特性。 编译器在生成消息类时处理 oneof 关键字。 使用 oneof 指定可能返回 Person 或 Error 的响应消息可能如下所示:
message Person {
// ...
}
message Error {
// ...
}
message ResponseMessage {
oneof result {
Error error = 1;
Person person = 2;
}
}
在整个消息声明中,oneof 集内的字段必须具有唯一的字段编号。
使用 oneof 时,生成的 C# 代码包括一个枚举,用于指定哪些字段已设置。 可以测试枚举来查找已设置的字段。 未设置的字段将返回 null 或默认值,而不是引发异常。
var response = await client.GetPersonAsync(new RequestMessage());
switch (response.ResultCase)
{
case ResponseMessage.ResultOneofCase.Person:
HandlePerson(response.Person);
break;
case ResponseMessage.ResultOneofCase.Error:
HandleError(response.Error);
break;
default:
throw new ArgumentException("Unexpected result.");
}
“值”
Value 类型表示动态类型的值。 它可以是 null、数字、字符串、布尔值、值字典 (Struct) 或值列表 (ValueList)。 Value 是一个 Protobuf 已知类型,它使用前面讨论的 oneof 功能。 若要使用 Value 类型,请导入 struct.proto
import "google/protobuf/struct.proto";
message Status {
// ...
google.protobuf.Value data = 3;
}
// Create dynamic values.
var status = new Status();
status.Data = Value.FromStruct(new Struct
{
Fields =
{
["enabled"] = Value.ForBoolean(true),
["metadata"] = Value.ForList(
Value.FromString("value1"),
Value.FromString("value2"))
}
});
// Read dynamic values.
switch (status.Data.KindCase)
{
case Value.KindOneofCase.StructValue:
foreach (var field in status.Data.StructValue.Fields)
{
// Read struct fields...
}
break;
// ...
}
直接使用 Value 可能很冗长。 使用 Value 的替代方法是通过 Protobuf 的内置支持,将消息映射到 JSON。 Protobuf 的 JsonFormatter 和 JsonWriter 类型可用于任何 Protobuf 消息。 Value 特别适用于与 JSON 进行转换。
以下是与之前的代码等效的 JSON:
// Create dynamic values from JSON.
var status = new Status();
status.Data = Value.Parser.ParseJson(@"{
""enabled"": true,
""metadata"": [ ""value1"", ""value2"" ]
}");
// Convert dynamic values to JSON.
// JSON can be read with a library like System.Text.Json or Newtonsoft.Json
var json = JsonFormatter.Default.Format(status.Metadata);
var document = JsonDocument.Parse(json);
dotnet-grpc文档地址
https://docs.microsoft.com/zh-cn/aspnet/core/grpc/?view=aspnetcore-7.0