首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在protobuf-net代码第一次Google.Protobuf.WellknownTypes.Any中使用(包) gRPC

如何在protobuf-net代码第一次Google.Protobuf.WellknownTypes.Any中使用(包) gRPC
EN

Stack Overflow用户
提问于 2021-12-07 12:21:01
回答 2查看 766关注 0票数 2

我正在创建一个gRPC服务,我们决定选择使用protobuf的代码优先方法。现在,我遇到了一个场景,我们有几个需要包装的类。我们不希望在KnownTypes类中定义MyMessage (只是说明问题的示例名称)。因此,我试图使用任何类型,目前给我一些困难的包装。

示例代码具有MyMessage,它定义了一些标头值,并且必须能够将任何类型作为有效负载传递。

代码语言:javascript
运行
复制
[ProtoContract]
public class MyMessage 
{
  [ProtoMember(1)] public int HeaderValue1 { get; set; }
  [ProtoMember(2)] public string HeaderValue2 { get; set; }
  [ProtoMember(3)] public Google.Protobuf.WellknownTypes.Any Payload { get; set; }
}

[ProtoContract]
public class Payload1 
{
  [ProtoMember(1)] public bool Data1   { get; set; }
  [ProtoMember(2)] public string Data2 { get; set; }
}

[ProtoContract]
public class Payload2 
{
  [ProtoMember(1)] public string Data1 { get; set; }
  [ProtoMember(2)] public string Data2 { get; set; }  
}

在代码的某个地方我用一个有效载荷构造我的消息..。

代码语言:javascript
运行
复制
  Payload2 payload = new Payload2 {
    Data1 = "abc",
    Data2 = "def"
  };
  
  MyMessage msg = new MyMessage 
  {
    HeaderValue1 = 123,
    HeaderValue2 = "iAmHeaderValue2",
    Payload = Google.Protobuf.WellknownTypes.Any.Pack(payload)
  };

这不起作用,因为Payload1Payload2需要实现Google.Protobuf.IMessage。因为我不知道怎么做,也找不到很多信息,所以我想知道我是否走错了路。

如何在protobuf-net?

  • Is中使用Any --一种将C#代码第一类打包到Google.Protobuf.WellknownTypes.Any?

  • Do中的简单(但兼容的)方法--我真的需要实现Google.Protobuf.IMessage?
EN

回答 2

Stack Overflow用户

发布于 2021-12-07 13:41:26

首先,既然您说“我们有一个需要包装的类--两个类--”(强调我的),我想知道您在这里真正想要的是oneof而不是Any。protobuf支持oneof的概念,尽管从代码优先的角度来看它并不明显。但想象一下我们(在合同第一意义上):

代码语言:javascript
运行
复制
syntax = "proto3";
message SomeType {
    oneof Content {
       Foo foo = 1;
       Bar bar = 2;
       Blap blap = 3;
    }
}

message Foo {}
message Bar {}
message Blap {}

这将实现如下(通过protobuf-net模式工具):

代码语言:javascript
运行
复制
private global::ProtoBuf.DiscriminatedUnionObject __pbn__Content;

[global::ProtoBuf.ProtoMember(1, Name = @"foo")]
public Foo Foo
{
    get => __pbn__Content.Is(1) ? ((Foo)__pbn__Content.Object) : default;
    set => __pbn__Content = new global::ProtoBuf.DiscriminatedUnionObject(1, value);
}
public bool ShouldSerializeFoo() => __pbn__Content.Is(1);
public void ResetFoo() => global::ProtoBuf.DiscriminatedUnionObject.Reset(ref __pbn__Content, 1);

[global::ProtoBuf.ProtoMember(2, Name = @"bar")]
public Bar Bar
{
    get => __pbn__Content.Is(2) ? ((Bar)__pbn__Content.Object) : default;
    set => __pbn__Content = new global::ProtoBuf.DiscriminatedUnionObject(2, value);
}
public bool ShouldSerializeBar() => __pbn__Content.Is(2);
public void ResetBar() => global::ProtoBuf.DiscriminatedUnionObject.Reset(ref __pbn__Content, 2);

[global::ProtoBuf.ProtoMember(3, Name = @"blap")]
public Blap Blap
{
    get => __pbn__Content.Is(3) ? ((Blap)__pbn__Content.Object) : default;
    set => __pbn__Content = new global::ProtoBuf.DiscriminatedUnionObject(3, value);
}
public bool ShouldSerializeBlap() => __pbn__Content.Is(3);
public void ResetBlap() => global::ProtoBuf.DiscriminatedUnionObject.Reset(ref __pbn__Content, 3);

可以选择使用枚举来帮助:

代码语言:javascript
运行
复制
public ContentOneofCase ContentCase => (ContentOneofCase)__pbn__Content.Discriminator;

public enum ContentOneofCase
{
    None = 0,
    Foo = 1,
    Bar = 2,
    Blap = 3,
}

这种方法可能比Any更容易,也更可取。

Any

短版本:到目前为止,protobuf还没有实现Any的任何特定请求。这可能不是一项巨大的工作-简单地说,它还没有发生。看起来,这里引用的是protobuf和Google,并使用了Any的Google实现。这很好,但是protobuf根本不打算使用它--它不知道在这种情况下Google,所以:实现IMessage实际上不会对您有所帮助。

我非常乐意和你一起看Any,从protobuf的角度看。最终,时间/可用性始终是限制因素,所以我优先考虑那些能够看到需求的特性。我认为您可能是第一个问我关于protobuf中Any的人。

票数 0
EN

Stack Overflow用户

发布于 2022-05-27 16:09:12

我的任何实现。

代码语言:javascript
运行
复制
[ProtoContract(Name = "type.googleapis.com/google.protobuf.Any")]
public class Any
{
    /// <summary>Pack <paramref name="value"/></summary>
    public static Any Pack(object? value)
    {
        // Handle null
        if (value == null) return new Any { TypeUrl = null!, Value = Array.Empty<byte>() };
        // Get type
        System.Type type = value.GetType();
        // Write here
        MemoryStream ms = new MemoryStream();
        // Serialize
        RuntimeTypeModel.Default.Serialize(ms, value);
        // Create any
        Any any = new Any
        {
            TypeUrl = $"{type.Assembly.GetName().Name}/{type.FullName}",
            Value = ms.ToArray()
        };
        // Return
        return any;
    }

    /// <summary>Unpack any record</summary>
    public object? Unpack()
    {
        // Handle null
        if (TypeUrl == null || Value == null || Value.Length == 0) return null;
        // Find '/'
        int slashIx = TypeUrl.IndexOf('/');
        // Convert to C# type name
        string typename = slashIx >= 0 ? $"{TypeUrl.Substring(slashIx + 1)}, {TypeUrl.Substring(0, slashIx)}" : TypeUrl;
        // Get type (Note security issue here!)
        System.Type type = System.Type.GetType(typename, true)!;
        // Deserialize
        object value = RuntimeTypeModel.Default.Deserialize(type, Value.AsMemory());
        // Return
        return value;
    }

    /// <summary>Test type</summary>
    public bool Is(System.Type type) => $"{type.Assembly.GetName().Name}/{type.FullName}" == TypeUrl;
      
    /// <summary>Type url (using C# type names)</summary>
    [ProtoMember(1)]
    public string TypeUrl = null!;
    /// <summary>Data serialization</summary>
    [ProtoMember(2)]
    public byte[] Value = null!;

    /// <summary></summary>
    public static implicit operator Container(Any value) => new Container(value.Unpack()! );
    /// <summary></summary>
    public static implicit operator Any(Container value) => Any.Pack(value.Value);

    /// <summary></summary>
    public struct Container
    {
        /// <summary></summary>
        public object? Value;
        /// <summary></summary>
        public Container()
        {
            this.Value = null;
        }

        /// <summary></summary>
        public Container(object? value)
        {
            this.Value = value;
        }
    }
}

'System.Object‘可以用作周围容器记录中的字段或属性:

代码语言:javascript
运行
复制
[DataContract]
public class Container
{
    /// <summary></summary>
    [DataMember(Order = 1, Name = nameof(Value))]
    public Any.Container Any { get => new Any.Container(Value); set => Value = value.Value; }
    /// <summary>Object</summary>
    public object? Value;
}

串行化

代码语言:javascript
运行
复制
    RuntimeTypeModel.Default.Add(typeof(Any.Container), false).SetSurrogate(typeof(Any));
    var ms = new MemoryStream();
    RuntimeTypeModel.Default.Serialize(ms, new Container { Value = "Hello world" });
    Container dummy = RuntimeTypeModel.Default.Deserialize(typeof(Container), ms.ToArray().AsMemory()) as Container;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70260050

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档