如何配置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(); } 

我得到以下exception:

不期望类型,也不能推断出合同:System.IdentityModel.Tokens.SessionSecurityToken

我尝试添加:

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

哪个超过exception,但我现在得到一个零字节数组。

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

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

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

抛出ProtoException:

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

BinaryFormatter能够毫不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)实现自定义序列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)); 

附:

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

请记住,这只是将一个序列化程序的输出作为原始数据嵌入到另一个序列化程序中。 幸运的是,protobuf-net很高兴谈论二进制文件,所以这不会增加任何明显的开销(只是blob的头部和长度前缀) – 但它也不会对SessionSecurityToken实例做任何特别聪明或聪明的事情。 如果这是你唯一要序列化的东西,那真的是不值得的。 如果这只是一个更大的DTO模型中的一个丑陋的碰撞,其中大部分可以很好地序列化 – 那么它可能会为你完成工作。