如何配置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();
}
我得到以下异常:
Type is not expected, and no contract can be inferred:
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:
No parameterless constructor found for 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模型中的一个丑陋凸起,其中大多数可以很好地序列化-那么它可能会为您完成工作.
标签:serialization,net-4-5,protobuf-net,c 来源: https://codeday.me/bug/20191030/1969708.html