protobuf-net适合序列化任意对象/领域模型吗?



我已经研究CQRS/ddd原则和模式有一段时间了,并且已经开始实现一个示例项目,在这个项目中,我将存储模型分成了一个WriteModel和一个ReadModel。WriteModel将使用一个简单的类似nosql的数据库,其中聚合以键值样式存储,值只是聚合的序列化版本。

我现在正在寻找ProtoBuf-Net来序列化和反序列化存储内外的领域模型聚合。除了这篇文章之外,我还没有找到在这个领域使用ProtoBuf-Net的任何指导或提示。关键是聚合的序列化和反序列化的(理想的)需求是域模型应该尽可能少地了解这个基础结构问题,这意味着以下内容:

  1. 类没有属性
  2. 没有构造函数、getter、setter或任何其他代码,只是为了序列化。
  3. 能够使用任何(自定义)类型,并有序列化/反序列化。

到目前为止,我只实现了聚合的第一个版本的序列化,它工作得很好。我使用RuntimeTypeModel.Default -实例在运行时配置元模型,并在任何地方使用UseConstructor = false,这使我能够将序列化机制与域程序集完全分离。我甚至实现了自定义的后反序列化机制,使我能够在ProtoBuf-Net反序列化为有效实例后及时初始化字段。假设我有一个AggregateA类,像这样:

[Version(1)]
public sealed class AggregateA
{
    private readonly int _x;
    private readonly string _y;
    ...
}

然后在我的序列化库中,我编写了如下代码:

var metaType = RuntimeTypeModel.Default.Add(typeof(AggregateA), false);
metaType.UseConstructor = false;
metaType.AddField(1, "_x");
metaType.AddField(2, "_y");
...

然而,我意识到到目前为止我只实现了基本的场景,现在我开始考虑如何处理模型的版本控制。我对更大的重构场景特别感兴趣,其中类型A被分成类型A1和A2,例如:

[Version(2)]
public sealed class AggregateA1
{
    private readonly int _x;
    ...
}
[Version(2)]
public sealed class AggregateA2
{
    private readonly string _y;
    ...
}

假设我有一堆AggregateA的序列化实例,但现在我的域模型只知道AggregateA1和AggregateA2,你会如何处理这种情况与ProtoBuf-Net?

第二个问题与第3点有关:如果您愿意投入一些额外的配置工作,ProtoBuf-Net是否能够处理任意类型?我读过关于使用DateTimeOffset类型时引发的异常,这使我认为不是所有类型都可以由框架开箱即用序列化,但是我可以通过在RuntimeTypeModel中注册它们来序列化这些类型吗?我应该去那里吗?或者最好忘记序列化常见的。net类型,而不是简单的类型?

protobuf-net 旨在使用可预测的已知模型。的确,一切都可以在运行时配置,但是我没有考虑如何处理您的A1/A2场景,正是因为不是一个受支持的场景(在我的辩护中,我看不到大多数序列化器都能很好地工作)。我的想法是,如果你有配置/映射数据,那么你可以简单地反序列化两次;也就是说,只要我们仍然告诉它AggregateA1._x映射到1, AggregateA2._y映射到2,你就可以这样做:

object a1 = model.Deserialize(source, null, typeof(AggregateA1));
source.Position = 0; // rewind
object a2 = model.Deserialize(source, null, typeof(AggregateA2));

但是,更复杂的调整需要额外的考虑。

Re"任意类型"…特别是,它支持"代理"类型,这对某些转换很有用——但如果没有非常具体的"问题陈述",很难完全回答。

概要:

protobuf-net有一个预期的用途,它包括序列化感知(属性等)和非感知场景(运行时配置等)——但它也适用于一系列定制场景(如果你愿意,可以使用原始的读写器API)。它不能也不能保证直接适合每一个可以想象的序列化场景,它的表现如何取决于你离那个场景有多远。

最新更新