您如何配置 protobuf-net 的 RuntimeModel.Default 以支持序列化/反序列化 SessionSecurityToken? [英] How do you configure protobuf-net's RuntimeModel.Default to support serializing/deserializing a SessionSecurityToken?

查看:26
本文介绍了您如何配置 protobuf-net 的 RuntimeModel.Default 以支持序列化/反序列化 SessionSecurityToken?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

BinaryFormatter 能够简单地处理序列化:

BinaryFormatter is able to handle serialization simply:

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 时:

When I tried replacing BinaryFormatter with protobuf-net:

using (var memoryStream = new MemoryStream())
{
    Serializer.Serialize(memoryStream, token);
    return memoryStream.ToArray();
}

我收到以下异常:

类型不是预期的,不能推断出合约:System.IdentityModel.Tokens.SessionSecurityToken

Type is not expected, and no contract can be inferred: System.IdentityModel.Tokens.SessionSecurityToken

我尝试添加:

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

通过异常但我现在得到一个零字节数组.

Which gets past the exception but I now get a zero byte array.

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

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

On the flipside, SessionSecurityToken does not have a parameterless constructor.

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

抛出一个 ProtoException:

Throws a ProtoException:

没有找到 SessionSecurityToken 的无参数构造函数

No parameterless constructor found for SessionSecurityToken

BinaryFormatter 可以毫不费力地做到这一点:

BinaryFormatter is able to do it without any fuss:

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 does not claim to be able to serialize every single type; indeed, you would have great difficulty serializing that via most serializers (XmlSerializer, any of the json serializers, DataContractSerializer, etc). BinaryFormatter is in a different category of serializers - and in this particular case, implements custom serialization via ISerializable.GetObjectData(SerializationInfo, StreamingContext).

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

The constructor thing is a red herring; actually, protobuf-net can bypass constructors completely, and in this particular scenario BinaryFormatter is using a custom serialization constructor via .ctor(SerializationInfo, StreamingContext).

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

For simple cases, protobuf-net can be configured via attributes or runtime options; for more complex scenarios, surrogates can be used to map between representations - however, in this case I would suggest (looking at the implementation of SessionSecurityToken) that this is more complex than you probably want to maintain.

我会在这里退后一两步;大多数序列化程序旨在处理数据,而不是实现 - 并且与 DTO 等配合得很好.SessionSecurityToken 非常不是 DTO,并且有不是在它们之间切换的简单方法.我强烈的建议是:序列化这个 代表什么,而不是它是什么.但是,如果这是现有复杂模型的一部分并且真的很难分离出来,您可以切换回 BinaryFormatter 获取这些位.我尚未对此进行测试,但请考虑:

I would step back a step or two here; most serializers are designed to work with data, not implementation - and work great with DTOs etc. SessionSecurityToken is very much not a DTO, and there is no simple way of switching between them. My strong suggestion here would be: serialize what this represents, not what it is. However, if this is part of an existing complex model and is really really hard to separate out, you could switch back to BinaryFormatter for those bits. I haven't tested this, but consider:

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<做任何特别聪明或聪明的事情/code> 实例.如果这是您正在序列化的唯一 东西,那真的不值得.如果这只是更大的 DTO 模型中的一个丑陋的凸起,其中大部分可以很好地序列化 - 那么它可能会为您完成工作.

Keep in mind that this simply embeds the output of one serializer as raw data inside another. Fortunately protobuf-net is happy talking binary, so this won't add any noticeable overhead (just the header and length-prefix for the blob) - but it also won't do anything particularly smart or clever with the SessionSecurityToken instances. If this is the only thing you are serializing, it really isn't worth it. If this is just one ugly bump in a larger DTO model, where most of it can serialize nicely - then it might get the job done for you.

这篇关于您如何配置 protobuf-net 的 RuntimeModel.Default 以支持序列化/反序列化 SessionSecurityToken?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆