2013-07-10 26 views
3

BinaryFormatter的是能够处理系列化简单:如何配置protobuf-net的RuntimeModel.Default以支持序列化/反序列化SessionSecurityToken?

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网替换的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?

+0

您无法使用protobuf序列化SessionSecurityToken,因为它会继承不可序列化的SecurityToken。你能告诉我,你可以将SessionSecurityToken转换为byte []或某种泛型类型的其他类型,并且可以返回SessionSecurityToken表单转换类型吗?那么我可以给你一个解决方案。 @DPeden – Rezoan

+0

你可以用SessionSecurityToken的成员创建一个新的自定义类,它可以从SessionSecurityToken成员中获取所有必要的数据吗? – Rezoan

+0

我有完全相同的问题,与另一种类型 - 但同样确切的问题 - 你有没有解决这个问题? – VisualBean

回答

4

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模型中的一个丑陋的凹凸,其中大部分可以很好地序列化 - 那么它可能会为你完成工作。

+0

感谢您花时间回复一些示例代码。我无法看到这一个星期。对不起,响应缓慢。 –

+0

Marc你在哪里调用RuntimeTypeModel.Default.Add。你会把它们放在整个项目的对象构造函数还是静态构造函数中?其次,ProtoBufFormatter.Model与RuntimeTypeModel,Default之间有什么区别。一个是WebAPI,一个是另一个nuget包? – rolls