使用 Protobuf-net 跨多个命名空间进行序列化
我一直在开发一个使用 protobuf-net (版本 2.0.0.480)来序列化消息的系统。该应用程序使用 CQRS 方法,其中命令和事件已分为不同的命名空间 [和程序集]。
该代码将在运行时动态添加任何继承自 MessageBase 的类的类型。这是使用下面的代码完成的:
// Used as a unique reference for each type in a member
private static int _sequence = 1000;
public static void RegisterAll()
{
RegisterAllDerivedFrom<MessageBase>();
}
public static void RegisterAllDerivedFrom<T>(params Assembly[] assemblies)
{
if (assemblies == null || assemblies.Length == 0)
{
assemblies = AppDomain.CurrentDomain.GetAssemblies();
}
var type = typeof(T);
var model = RuntimeTypeModel.Default;
var metaModel = model.Add(type, true);
RegisterAllBaseTypes(type, metaModel, model, assemblies);
}
private static void RegisterAllBaseTypes(Type type, MetaType metaModel, RuntimeTypeModel model, params Assembly[] assemblies)
{
foreach (var t in assemblies.SelectMany(a => a.GetTypes().Where(t => t.BaseType != null && t.BaseType == type)))
{
var subModel = model.Add(t, true);
metaModel.AddSubType(_sequence, t);
_sequence++;
RegisterAllBaseTypes(t, subModel, model, assemblies);
}
}
还将一些类型手动添加到默认运行时类型模型:
RuntimeTypeModel.Default.Add(typeof(ReferenceNumber), true)
.AddSubType(100, typeof(Product))
.AddSubType(110, typeof(ProductGroup));
当所有消息都在时,以上所有内容似乎都工作正常:
逻辑分组.事件
项目向前推进并添加了新的命名空间:
ReferenceGrouping.Commands
一旦添加ReferenceGrouping.Commands并尝试发送消息,就会抛出ProtoException。我发现此行为的唯一解决方法是将 ReferenceGrouping.Commands 中的命令添加到 LogicalGrouping.Events 中。
这是预期的行为还是 RuntimeTypeModel 应该能够支持从完全不同的命名空间添加的类?
I have been working on a system which I'm using protobuf-net (version 2.0.0.480) for serializing messages. This application uses a CQRS approach in which commands and events have been separated into different namespaces [and assemblies].
The code will dynamically add the types at runtime for any class that inherits from MessageBase. This is done using the code below:
// Used as a unique reference for each type in a member
private static int _sequence = 1000;
public static void RegisterAll()
{
RegisterAllDerivedFrom<MessageBase>();
}
public static void RegisterAllDerivedFrom<T>(params Assembly[] assemblies)
{
if (assemblies == null || assemblies.Length == 0)
{
assemblies = AppDomain.CurrentDomain.GetAssemblies();
}
var type = typeof(T);
var model = RuntimeTypeModel.Default;
var metaModel = model.Add(type, true);
RegisterAllBaseTypes(type, metaModel, model, assemblies);
}
private static void RegisterAllBaseTypes(Type type, MetaType metaModel, RuntimeTypeModel model, params Assembly[] assemblies)
{
foreach (var t in assemblies.SelectMany(a => a.GetTypes().Where(t => t.BaseType != null && t.BaseType == type)))
{
var subModel = model.Add(t, true);
metaModel.AddSubType(_sequence, t);
_sequence++;
RegisterAllBaseTypes(t, subModel, model, assemblies);
}
}
A few types are added manually to the Default RuntimeTypeModel as well:
RuntimeTypeModel.Default.Add(typeof(ReferenceNumber), true)
.AddSubType(100, typeof(Product))
.AddSubType(110, typeof(ProductGroup));
All the above seems to work fine when all messages were in:
LogicalGrouping.Events
The project moved forward and a new namespace was added:
ReferenceGrouping.Commands
Once ReferenceGrouping.Commands is added and attempts to send a message a ProtoException is thrown. The only workaround that I found for this behaviour is to add the Commands from ReferenceGrouping.Commands into LogicalGrouping.Events.
Is this the anticipated behaviour or should the RuntimeTypeModel be able to support classes being added from completely different namespaces?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据我的评论,Protobuf-net 根本不关心命名空间、类型名称或成员名称,因为它使用数字键作为标识符(根据 protobuf 规范)。这意味着只要数字有意义,您就可以在不同的程序集中对完全不同的模型进行反序列化。
查看代码,我强烈怀疑问题是您没有可靠的(可重复的)子类型标识符。如果有,则在序列化时:
然后,在配置模型进行反序列化时,兼容的键至关重要;例如,您可以反序列化为:
我的猜测是,您添加子类型的机制并不能确保数字匹配。它需要一些线索。实际上,看看你的代码,我想知道它目前是否也会中断,如果:
我的建议是:保留外部注册每个键在子类型方面的含义。或者:使用 ProtoIncludeAttribute 在代码中执行相同的操作。
Protobuf-net, as per my comment, simply does not care about namespaces, type names or member-names, since it uses numeric keys as identifiers (in accordance with the protobuf spec). This means you can deserialize on a completely different model in dfferent assemblies, as long as the numbers make sense.
Looking at the code, I strongly suspect the problem is that you don't have reliable (repeatable) sub-type identifiers. If you have, when serializing:
Then it is vitally important, when configuring the models for deserialization, keys that are compatible; for example you could deserialize into:
My guess is that your mechanism for adding sub-types is not ensuring the numbers match. It needs some clue. Actually, looking at your code I wonder if it could also break currently if:
My advice would be: keep an external registration somewhere of what each key means in terms of sub-types. Or: do the same in code using ProtoIncludeAttribute.