如何配置 protobuf-net 的 RuntimeModel.Default 以支持序列化/反序列化 SessionSecurityToken?



BinaryFormatter能够简单地处理序列化:

private byte[] TokenToBytes(SessionSecurityToken token)
{
    if (token == null)
    {
        return null;
    }
    using (var memoryStream = new MemoryStream())
    {
        var binaryFormatter = new BinaryFormatter();
        binaryFormatter.Serialize(memoryStream, token);
        return memoryStream.ToArray();
    }
}

当我尝试用protobuf-net:替换BinaryFormatter时

using (var memoryStream = new MemoryStream())
{
    Serializer.Serialize(memoryStream, token);
    return memoryStream.ToArray();
}

我得到以下异常:

类型不应为,并且无法推断出任何合同:System.IdentityModel.Tokens.SessionSecurityToken

我试着添加:

RuntimeTypeModel.Default.Add(typeof(SessionSecurityToken), true);

它通过了异常,但我现在得到了一个零字节数组。

如何正确配置protobuf-net以序列化SessionSecurityToken

另一方面,SessionSecurityToken没有无参数构造函数。

using (var memoryStream = new MemoryStream(tokenAsBytes))
{
    return Serializer.Deserialize<SessionSecurityToken>(memoryStream);
}

抛出ProtoException:

找不到SessionSecurityToken 的无参数构造函数

BinaryFormatter能够做到这一点而不必大惊小怪:

using (var memoryStream = new MemoryStream(bytes))
{
    var binaryFormatter = new BinaryFormatter();
    return (SessionSecurityToken)binaryFormatter.Deserialize(memoryStream);
}

如何正确配置protobuf-net以反序列化SessionSecurityToken

protobuf-net并不声称能够序列化每一个类型;事实上,通过大多数序列化程序(XmlSerializer、任何json序列化程序、DataContractSerializer等)进行序列化都会遇到很大困难。BinaryFormatter属于不同的序列化程序类别,在这种特殊情况下,它通过ISerializable.GetObjectData(SerializationInfo, StreamingContext)实现自定义序列化。

构造函数是转移注意力;实际上,protobuf-net可以完全绕过构造函数,在这个特定的场景中,BinaryFormatter通过.ctor(SerializationInfo, StreamingContext)使用自定义序列化构造函数。

对于简单的情况,protobuf-net可以通过属性或运行时选项进行配置;对于更复杂的场景,代理可以用于在表示之间进行映射——然而,在这种情况下,我建议(查看SessionSecurityToken的实现)这比您可能想要维护的更复杂。

我会在这里后退一两步;大多数串行器被设计为使用数据,而不是实现,并且可以很好地使用DTO等。SessionSecurityToken在很大程度上是而不是DTO,并且没有简单的方法在它们之间切换。我强烈建议:序列化这个代表的,而不是它是什么。然而,如果这是现有复杂模型的一部分,并且真的很难分离,那么您可以切换回BinaryFormatter来处理这些位。我还没有测试过,但考虑一下:

RuntimeTypeModel.Default.Add(typeof(SessionSecurityToken), false)
        .SetSurrogate(typeof(BinaryFormatterSurrogate<SessionSecurityToken>));

带有:

[ProtoContract]
public class BinaryFormatterSurrogate<T>
{
    [ProtoMember(1)]
    public byte[] Raw { get; set; }
    public static explicit operator T(BinaryFormatterSurrogate<T> value)
    {
        if(value==null || value.Raw == null) return default(T);
        using(var ms = new MemoryStream(value.Raw))
        {
            return (T)new BinaryFormatter().Deserialize(ms);
        }
    }
    public static explicit operator BinaryFormatterSurrogate<T>(T value)
    {
        object obj = value;
        if (obj == null) return null;
        using (var ms = new MemoryStream())
        {
            new BinaryFormatter().Serialize(ms, obj);
            return new BinaryFormatterSurrogate<T> { Raw = ms.ToArray() };
        }
    }
}

请记住,这只是将一个序列化程序的输出作为原始数据嵌入到另一个序列化器中。幸运的是,protobuf-net是一个乐于使用二进制的网络,因此这不会增加任何明显的开销(只有blob的头部和长度前缀),但它也不会对SessionSecurityToken实例做任何特别聪明或聪明的事情。如果这是你正在序列化的唯一的东西,那真的不值得。如果这只是一个更大的DTO模型中的一个丑陋的凸起,其中大部分都可以很好地序列化,那么它可能会为你完成任务。

最新更新