【问题标题】:How do you configure protobuf-net's RuntimeModel.Default to support serializing/deserializing a SessionSecurityToken?如何配置 protobuf-net 的 RuntimeModel.Default 以支持序列化/反序列化 SessionSecurityToken?
【发布时间】:2013-07-10 06:09:56
【问题描述】:

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 序列化 SessionSecurityToken,因为它继承了不可序列化的 SecurityToken。您能否告诉我,您可以将 SessionSecurityToken 转换为其他类型,例如 byte[] 或某种泛型类型,并且可以取回 SessionSecurityToken 形式的转换类型吗?那么我可以给你一个解决方案。 @DPeden
  • 你能用 SessionSecurityToken 的成员创建一个新的自定义类,它可以从 SessionSecurityToken 成员那里获取所有必要的数据吗?
  • 我遇到了完全相同的问题,但有另一种类型 - 但同样的问题 - 你解决过这个问题吗?
  • 我一直使用 BinaryFormatter,因为它可以正常工作,正如 Marc 在他的最后一句话中提到的那样,跳过箍是不值得的,因为这是我唯一要序列化的东西,而不是更大的模型.

标签: c# serialization .net-4.5 protobuf-net


【解决方案1】:

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

构造函数是一条红鲱鱼;实际上,protobuf-net 可以完全绕过构造函数,在这种特殊情况下,BinaryFormatter 正在通过.ctor(SerializationInfo, StreamingContext) 使用自定义序列化构造函数。

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

我会在这里退一两步;大多数序列化程序都设计为使用 data,而不是实现 - 并且可以很好地使用 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 模型中的一个丑陋的凸起,其中大部分可以很好地序列化 - 那么它可能会为您完成工作。

【讨论】:

  • 感谢您花时间回复一些示例代码。我无法看这个大约一个星期。抱歉回复慢。
  • Marc 你在哪里调用 RuntimeTypeModel.Default.Add。您会将它们放在对象构造函数中还是放在整个项目的静态构造函数中?其次,ProtoBufFormatter.Model 与 RuntimeTypeModel,Default 有什么区别。一个用于 WebAPI,一个用于另一个 nuget 包?
猜你喜欢
  • 2012-04-26
  • 2014-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多