在 protobuf-net 中序列化 IEnumerable

Posted

技术标签:

【中文标题】在 protobuf-net 中序列化 IEnumerable【英文标题】:Serializing an IEnumerable in protobuf-net 【发布时间】:2020-11-17 03:20:28 【问题描述】:

我有一个相当重量级的 DTO 库,目前一些 WCF 服务正在使用它。我们正试图将它带入 protobuf-net 世界,尽可能少地进行修改。一组特定的项目给我序列化带来了麻烦。我将在这里简单介绍它们,因为它有点复杂,但问题的要点是:

public class Key

   public string Id get; set;


public class KeyCollection : IEnumerable<Key>

   private readonly List<Key> list;

#region IEnumerable
   // etc...
#endregion


public class Item

   public long Id  get; set; 


public abstract class ContainerBase
 

public abstract class ContainerBase<T> : ContainerBase
   where T : Item
 

public abstract class ContainerType1Base : ContainerBase<Item>

   public KeyCollection Keys  get; set; 


public class ContainerType1 : ContainerType1Base
 

我省略了装饰器,因为我不认为它们是问题,主要是因为如果我将 void Add(Key item) 添加到 KeyCollection 整个事情似乎工作。否则,我在尝试序列化 ContainerType1 的实例时遇到问题。

实际上,更改KeyCollection 的签名有点令人望而却步,因此我尝试按照this answer 尝试以编程方式进行。具体来说,将ContainerType1ContainerType1BaseContainerBase&lt;Item&gt; 的“键”ValueMember 上的itemTypedefaultType 设置为null。我还在KeyCollection 上将IgnoreListHandling 设置为true... 这完全不起作用。我在客户端上收到一个通用的“无法反序列化”异常,如果有帮助,我可以在这里发布。在服务器端,我使用Serializer.Serialize() 将其序列化出来,并吐出Serializer.GetProto&lt;&gt;() 以及对象的JSON,它们似乎都可以正常工作。

如何关闭列表处理?与此相关,有没有办法在序列化时打开额外的调试以尝试获取有关问题的更多信息?

【问题讨论】:

IgnoreListHandling 应该绝对有效。您是否有一个 runnable 最小的复制品,我可以看到与您看到的相同的东西?细节可能很重要。另外,您使用的是什么库版本?谢谢。 我可以尝试制作一个我可以分享的小型 repo 来展示这种行为。我正在使用 protobuf-net.Grpc.Native,v1.0.123。 我忘了提到(或者说它看起来并不重要,但实际上可能是)这是在 Grpc 调用的上下文中完成的。所以整个ContainerType1 被某个方法回复返回。 好吧,我写了这两个库,所以...我应该能够提供帮助 :) 复制真的很有帮助(顺便说一句;如果你用更新 - 尝试@我,即@foof - 这让我得到通知更可靠) @MarcGravell 你说得对,我尝试用 DTO 库的一小部分来重现我的问题,我能够 1、重现它和 2、IgnoreListHandling 我的出路。原来的 DTO 库仍在进行反序列化。有没有办法打开更多的调试信息?我得到的只是“无法反序列化”。 【参考方案1】:

基本上,显示的代码看起来不错。不幸的是,目前有一个"feature" in gRPC,这意味着当编组器(序列化器)由于某种原因失败时,它会丢弃原始异常,因此 gRPC 目前不会暴露实际问题。我已为此提交了修复程序 - 它可能会被接受,也可能不会被接受。

在此期间,我建议您简单地从等式中删除 gRPC,并仅模拟编组器工作负载;为此,在服务器上:生成您要发送的数据,然后执行:

var ms = new MemoryStream();
Serializer.Serialize(ms, yourDataHere);
var payload = Convert.ToBase64String(ms.ToArray());

并获取payload 的值(这只是一个string)。现在在客户端,反转这个:

var ms = new MemoryStream(Convert.FromBase64String(thatStringValue));
Serialize.Deserialize<YourTypeHere>(ms);

我的期望是这应该抛出一个异常,告诉你实际问题是什么。


如果 gRPC 更改被合并,则故障应该可通过以下方式获得:

catch (RpcException fault)

    var originalFault = fault.Status.DebugException;
    // ^^^

【讨论】:

以上是关于在 protobuf-net 中序列化 IEnumerable的主要内容,如果未能解决你的问题,请参考以下文章

关于在 C# 中使用 Protobuf-Net

protobuf-net - 在 C++ 端反序列化的问题:(

protobuf-net 中没有为 System.Version 定义序列化程序

负载平衡系统中的 Protobuf-net 动态类型

意外的 protobuf-net 序列化程序行为

用 Protobuf-net 替换 binaryformatter