在 protobuf-net 中序列化一个 IEnumerable
Serializing an IEnumerable in protobuf-net
我有一个相当重量级的 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
的签名有点令人望而却步,因此我试图按照 尝试以编程方式进行。具体来说,在 ContainerType1
、ContainerType1Base
和 ContainerBase<Item>
的“键”ValueMember
上将 itemType
和 defaultType
设置为空。我还在 KeyCollection
上将 IgnoreListHandling
设置为 true
... 这完全不起作用。我在客户端收到一个通用的“反序列化失败”异常,如果有帮助,我可以在此处post。在服务器端,我使用 Serializer.Serialize()
将其序列化,然后吐出对象的 Serializer.GetProto<>()
和 JSON,它们似乎都可以正常工作。
如何关闭列表处理?与此相关,有没有办法在序列化时打开额外的调试以尝试获取有关问题的更多信息?
基本上,显示的代码看起来不错。不幸的是,目前有一个 "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;
// ^^^
}
我有一个相当重量级的 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
的签名有点令人望而却步,因此我试图按照 ContainerType1
、ContainerType1Base
和 ContainerBase<Item>
的“键”ValueMember
上将 itemType
和 defaultType
设置为空。我还在 KeyCollection
上将 IgnoreListHandling
设置为 true
... 这完全不起作用。我在客户端收到一个通用的“反序列化失败”异常,如果有帮助,我可以在此处post。在服务器端,我使用 Serializer.Serialize()
将其序列化,然后吐出对象的 Serializer.GetProto<>()
和 JSON,它们似乎都可以正常工作。
如何关闭列表处理?与此相关,有没有办法在序列化时打开额外的调试以尝试获取有关问题的更多信息?
基本上,显示的代码看起来不错。不幸的是,目前有一个 "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;
// ^^^
}