zoukankan      html  css  js  c++  java
  • Protobuf

    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,这不会引发错误。

    表 3
    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

     

    字节

    使用 ByteString.CopyFrom(byte[] data) 从字节数组创建新实例:

    var data = await File.ReadAllBytesAsync(path);
    
    var payload = new PayloadResponse();
    payload.Data = ByteString.CopyFrom(data);

    使用 ByteString.Span 或 ByteString.Memory 直接访问 ByteString 数据。 或调用 ByteString.ToByteArray() 将实例转换回字节数组:

    var payload = await client.GetPayload(new PayloadRequest());
    
    await File.WriteAllBytesAsync(path, payload.Data.ToByteArray());

    日期和时间

    本机标量类型不提供与 .NET 的 DateTimeOffsetDateTime 和 TimeSpan 等效的日期和时间值。 可使用 Protobuf 的一些“已知类型”扩展来指定这些类型。

    日期和时间
    .NET 类型Protobuf 已知类型
    DateTimeOffset google.protobuf.Timestamp
    DateTime google.protobuf.Timestamp
    TimeSpan google.protobuf.Duration
    syntax = "proto3"
    
    import "google/protobuf/duration.proto";  
    import "google/protobuf/timestamp.proto";
    
    message Meeting {
        string subject = 1;
        google.protobuf.Timestamp start = 2;
        google.protobuf.Duration duration = 3;
    }

    C# 类中生成的属性不是 .NET 日期和时间类型。 属性使用 Google.Protobuf.WellKnownTypes 命名空间中的 Timestamp 和 Duration 类。 这些类提供在 DateTimeOffsetDateTime 和 TimeSpan 之间进行转换的方法。

    // Create Timestamp and Duration from .NET DateTimeOffset and TimeSpan.
    var meeting = new Meeting
    {
        Time = Timestamp.FromDateTimeOffset(meetingTime), // also FromDateTime()
        Duration = Duration.FromTimeSpan(meetingLength)
    };
    
    // Convert Timestamp and Duration to .NET DateTimeOffset and TimeSpan.
    var time = meeting.Time.ToDateTimeOffset();
    var duration = meeting.Duration?.ToTimeSpan();

    Timestamp 类型适用于 UTC 时间。 DateTimeOffset 值的偏移量始终为零,并且 DateTime.Kind 属性始终为 DateTimeKind.Utc

    列表

    Protobuf 中,在字段上使用 repeated 前缀关键字指定列表

    message Person {
        // ...
        repeated string roles = 8;
    }
    
    public class Person
    {
        // ...
        public RepeatedField<string> Roles { get; }
    }

    字典

    .NET IDictionary<TKey,TValue> 类型在 Protobuf 中使用 map<key_type, value_type> 表示

    message Person {
        // ...
        map<string, string> attributes = 9;
    }

    在生成的 .NET 代码中,map 字段由 Google.Protobuf.Collections.MapField<TKey, TValue> 泛型类型表示。

    无结构的条件消息

    Protobuf 是一种协定优先的消息传递格式。 构建应用时,必须在 .proto 文件中指定应用的消息,包括其字段和类型。 Protobuf 的协定优先设计非常适合强制执行消息内容,但可能会限制不需要严格协定的情况:

    • 包含未知有效负载的消息。 例如,具有可以包含任何消息的字段的消息。
    • 条件消息。 例如,从 gRPC 服务返回的消息可能是成功结果或错误结果。
    • 动态值。 例如,具有包含非结构化值集合的字段的消息,类似于 JSON。

    Protobuf 提供语言功能和类型来支持这些情况。

    任意

    利用 Any 类型,可以将消息作为嵌入类型使用,而无需 .proto 定义。 若要使用 Any 类型,请导入 any.proto

    import "google/protobuf/any.proto";
    
    message Status {
        string message = 1;
        google.protobuf.Any detail = 2;
    }
    
    // Create a status with a Person message set to detail.
    var status = new ErrorStatus();
    status.Detail = Any.Pack(new Person { FirstName = "James" });
    
    // Read Person message from detail.
    if (status.Detail.Is(Person.Descriptor))
    {
        var person = status.Detail.Unpack<Person>();
        // ...
    }

     

    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

     dotnet-grpc 是一种 .NET Core 全局工具,用于在 .NET gRPC 项目中管理 Protobuf (.proto) 引用。 该工具可以用于添加、刷新、删除和列出 Protobuf 引用。

    dotnet tool install -g dotnet-grpc

    dotnet-grpc 可以用于将 Protobuf 引用作为 <Protobuf /> 项添加到 .csproj 文件

    dotnet-grpc 工具可以:

    • 从磁盘上的本地文件创建 Protobuf 引用。
    • 从 URL 指定的远程文件创建 Protobuf 引用。
    • 确保将正确的 gRPC 包依赖项添加到项目。

    例如,将 Grpc.AspNetCore 包添加到 Web 应用。 Grpc.AspNetCore 包含 gRPC 服务器和客户端库以及工具支持。 或者,将 Grpc.Net.ClientGrpc.Tools 和 Google.Protobuf 包(其中仅包含 gRPC 客户端库和工具支持)添加到控制台应用。

    参见

    https://docs.microsoft.com/zh-cn/aspnet/core/grpc/dotnet-grpc?view=aspnetcore-3.1

  • 相关阅读:
    centos 卸载自带的apache
    静态方法绑定
    安装apc
    避免SSH连接因超时闲置断开
    svn使用安全问题
    接口类,和抽象类。
    function (规定参数必须为某个对象的实例)
    jquery 获取DIV边框的宽
    正则表达式(非捕获)
    Linux ftp服务器Proftp配置
  • 原文地址:https://www.cnblogs.com/yetsen/p/13762078.html
Copyright © 2011-2022 走看看