How to serialize an ISerializable object into SOAP or Json or Xml

浪子不回头ぞ 提交于 2019-12-02 11:46:00

Json.NET does in fact support nonpublic streaming serialization constructors for ISerializable types. For confirmation see the source code for DefaultContractResolver.CreateISerializableContract().

Your actual problem is that the ISerializable type in question is also a collection, and it appears Json.NET uses an array contract in preference to a JsonISerializableContract for such types, as shown in DefaultContractResolver.CreateContract():

        if (typeof(IEnumerable).IsAssignableFrom(t))
        {
            return CreateArrayContract(objectType);
        }

        if (CanConvertToString(t))
        {
            return CreateStringContract(objectType);
        }

#if !(DOTNET || PORTABLE40 || PORTABLE)
        if (!IgnoreSerializableInterface && typeof(ISerializable).IsAssignableFrom(t))
        {
            return CreateISerializableContract(objectType);
        }
#endif

To work around this problem, you can create your own custom contract resolver that reverses this logic:

public class ISerializableCollectionContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        var contract = base.CreateContract(objectType);
        var underlyingType = Nullable.GetUnderlyingType(objectType) ?? objectType;

        if (!IgnoreSerializableInterface 
            && typeof(ISerializable).IsAssignableFrom(underlyingType)
            && contract is JsonArrayContract
            && !underlyingType.GetCustomAttributes<JsonContainerAttribute>().Any())
        {
            contract = CreateISerializableContract(objectType);
        }

        return contract;
    }
}

Your custom collections should now be serialized through their ISerializable interface.

You may want to cache the contract resolver for best performance.

DataContractSerializer and DataContractJsonSerializer both support ISerializable. See Types Supported by the Data Contract Serializer.

For instance, consider the following class:

[Serializable]
public class SerializableClass : ISerializable
{
    readonly int valueField;

    public SerializableClass(int valueField)
    {
        this.valueField = valueField;
    }

    public int Value { get { return valueField; } }

    #region ISerializable Members

    protected SerializableClass(SerializationInfo info, StreamingContext context)
    {
        this.valueField = info.GetInt32("valueField");
    }

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("valueField", valueField);
    }

    #endregion
}

And following helper methods:

public static partial class DataContractSerializerHelper
{
    public static string SerializeXml<T>(T obj, DataContractSerializer serializer = null, XmlWriterSettings settings = null)
    {
        serializer = serializer ?? new DataContractSerializer(obj.GetType());
        using (var textWriter = new StringWriter())
        {
            settings = settings ?? new XmlWriterSettings { Indent = true, IndentChars = "    " };
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
            {
                serializer.WriteObject(xmlWriter, obj);
            }
            return textWriter.ToString();
        }
    }

    public static T DeserializeXml<T>(string xml, DataContractSerializer serializer = null)
    {
        using (var textReader = new StringReader(xml ?? ""))
        using (var xmlReader = XmlReader.Create(textReader))
        {
            return (T)(serializer ?? new DataContractSerializer(typeof(T))).ReadObject(xmlReader);
        }
    }
}

public static partial class DataContractJsonSerializerHelper
{
    private static MemoryStream GenerateStreamFromString(string value)
    {
        return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
    }

    public static string SerializeJson<T>(T obj, DataContractJsonSerializer serializer = null)
    {
        serializer = serializer ?? new DataContractJsonSerializer(obj.GetType());
        using (var memory = new MemoryStream())
        {
            serializer.WriteObject(memory, obj);
            memory.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(memory))
            {
                return reader.ReadToEnd();
            }
        }
    }

    public static T DeserializeJson<T>(string json, DataContractJsonSerializer serializer = null)
    {
        serializer = serializer ?? new DataContractJsonSerializer(typeof(T));
        using (var stream = GenerateStreamFromString(json))
        {
            var obj = serializer.ReadObject(stream);
            return (T)obj;
        }
    }
}

Then

var test = new SerializableClass(42);

var xml = DataContractSerializerHelper.SerializeXml(test);
Debug.WriteLine(xml);

Produces

<SerializableClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.datacontract.org/2004/07/Question38188639">
    <valueField i:type="x:int" xmlns="">42</valueField>
</SerializableClass>

And

var json = DataContractJsonSerializerHelper.SerializeJson(test);
Debug.WriteLine(json);

Produces

{"valueField":42}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!