C# 如何配置protobuf net';s RuntimeModel.Default是否支持序列化/反序列化SessionSecurityToken?

C# 如何配置protobuf net';s RuntimeModel.Default是否支持序列化/反序列化SessionSecurityToken?,c#,serialization,.net-4.5,protobuf-net,C#,Serialization,.net 4.5,Protobuf Net,BinaryFormatter能够简单地处理序列化: private byte[] TokenToBytes(SessionSecurityToken token) { if (token == null) { return null; } using (var memoryStream = new MemoryStream()) { var binaryFormatter = new BinaryFormatter();

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);
}

如何正确配置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>));
RuntimeTypeModel.Default.Add(typeof(SessionSecurityToken),false)
.SetSurrogate(typeof(binaryFormatterSubrogate));
与:

[协议]
公共类BinaryFormatterSubrogate
{
[原成员(1)]
公共字节[]原始{get;set;}
公共静态显式运算符T(BinaryFormatterSubrogate值)
{
if(value==null | | value.Raw==null)返回默认值(T);
使用(var ms=newmemoryStream(value.Raw))
{
返回(T)新的BinaryFormatter()。反序列化(ms);
}
}
公共静态显式运算符BinaryFormatterSubrogate(T值)
{
对象obj=值;
if(obj==null)返回null;
使用(var ms=new MemoryStream())
{
新的BinaryFormatter().Serialize(ms,obj);
返回新的BinaryFormatterSubrogate{Raw=ms.ToArray()};
}
}
}

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

您无法使用protobuf序列化SessionSecurityToken,因为它继承了不可序列化的SecurityToken。您能告诉我,您能将SessionSecurityToken转换为其他类型,如byte[]或某种泛型类型,并能从转换后的类型返回SessionSecurityToken吗?然后我可以给你一个解决方案@dpeden你能用SessionSecurityToken的成员创建一个新的自定义类,它可以从SessionSecurityToken成员获取所有必要的数据吗?我有完全相同的问题,另一种类型-但同样的问题-你解决过这个问题吗?我一直使用BinaryFormatter,正如Marc在最后一句中提到的,这是我唯一要序列化的东西,而不是一个更大的模型。感谢您花时间回复一些示例代码。我有一个星期没能看到这个。抱歉,响应太慢。Marc您将对RuntimeTypeModel.Default.Add的调用放在哪里。您是将它们放在整个项目的对象构造函数中还是静态构造函数中?其次,ProtoBufferMatter.Model与RuntimeTypeModel(默认)之间的区别是什么。一个用于WebAPI,一个用于另一个nuget包?
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() };
        }

    }
}