我一直在探索 CQRS/DDD 原则和模式一段时间,并开始实施一个示例项目,在该项目中我将存储模型拆分为 WriteModel 和 ReadModel。WriteModel 将使用一个简单的类似 NoSQL 的数据库,其中聚合以键值样式存储,值只是聚合的序列化版本。
我现在正在使用 ProtoBuf-Net 对我的域模型聚合进出存储进行序列化和反序列化。除了这篇文章,我还没有找到在这个领域使用 ProtoBuf-Net 的任何指导或技巧。关键是聚合的序列化和反序列化的(理想)要求是域模型应该尽可能少地了解这个基础设施问题,这意味着以下内容:
- 类上没有属性
- 没有构造函数、getter、setter 或任何其他代码,只是为了序列化。
- 能够使用任何(自定义)类型并对其进行序列化/反序列化。
到目前为止,我只实现了我的聚合的第一个版本的序列化,它工作得非常好。我使用RuntimeTypeModel.Default
-instance 在运行时配置 MetaModel 并且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
-type 时引发的异常,这让我认为并非所有类型都可以由框架开箱即用地序列化,但我可以通过在 RuntimeTypeModel 中注册这些类型来序列化它们吗?我应该去那里吗?还是最好忘记序列化除简单类型之外的常见 .NET 类型?