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

Protobuf-net dynamic types in a load-balanced system

我在一个应用程序中使用 protobuf-net,该应用程序对来自(出于所有意图和目的)第 3 方 dll 的对象进行大量二进制序列化。因此,我无法在合同本身上使用 [Proto-] 属性,而是使用 RuntimeTypeModel 在 运行 遇到新类型时准备序列化程序。示例序列化程序包装器:

public static class ProtobufSerializer
{
    public static byte[] Serialize<T>(T obj)
    {
         PrepareSerializer(typeof(T));
         ProtoBuf.Serialize(memoryStream, obj); 
    }

    public static T Deserialize<T>(byte[] bytes)
    {
         PrepareSerializer(typeof(T));
         ProtoBuf.Serialize(memoryStream, obj); 
    }
}

我们可以安全地假设 PrepareSerializer 能够准备 RuntimeTypeModel 序列化任何给定的类型。我在对象的反序列化方面遇到了一些问题,但我必须利用 DynamicType=true。例如,给定以下界面:

public interface IFoo
{
    string Name {get;}
}

和实施:

public class Foo : IFoo
{
    public string Name {get;set;}
    public Bar Bar {get;set;}

    [OnDeserializing]
    public void OnDeserializing(Type t)
    {
        PrepareSerializer(typeof(Foo));
    }
}

public class Bar
{
    public int Baz {get;set;}
}

PrepareSerializer 方法本质上会使用代理并生成大致相当于:

的模型
// registered surrogate for IFoo
[ProtoContract]
public class IFooSurrogate
{
    [ProtoMember(1, DynamicType=true)]
    public object Value

    [OnSerializing]
    public void OnSerializing(Type t)
    {
        PrepareSerializer(this.Value.GetType());
    }
}

其中 Value 由隐式转换器设置为等于 IFoo 的实例。这在序列化期间工作正常(事件被触发并让我有机会为特定接口实现类型准备序列化程序)。它在非分布式系统中也能正常工作,在非分布式系统中我必须 运行 通过序列化方法才能尝试反序列化该类型。但是,在分布式系统中的反序列化过程中,当前节点以前从未见过 Foo,ProtoBuf.Serializer 抛出一个 InvalidOperationException 抱怨缺少类型 Bar 之前的序列化程序 运行 是 Foo.OnDeserializing 事件(让我有机会告诉它如何反序列化 Bar)。

在 protobuf-net 抱怨缺少序列化器之前,有什么方法可以附加一个钩子来确保我的代码有机会了解 'Foo'?

我还没有完全尝试过这种情况,但是:为了允许一些灵活性,所有 Type 存储和再水化都通过 TypeModel.DynamicTypeFormatting 事件进行;所以,理论上你 可以 将这个事件挂接到 RuntimeTypeModel.Default,像这样:

RuntimeTypeModel.DynamicTypeFormatting += (sender, args) => {
    if (args.FormattedName != null) { // meaning: rehydrating
        lock(SomeSyncLock) {
            if(NotYetKnown(args.FormattedName))
                Prepare(args.FormattedName);
        }
    }
};

此 API 的 intent 是为了让您控制类型的解析方式,但是...我想它也适用于此吗?


但是,我可以理解在第一次看到新的 Type 时更有针对性的事件的想法,本质上是替换/补充 "apply default behaviour" 代码。不过,我认为 今天 不存在。