ExtensionDataObject not marked as serializable

与世无争的帅哥 提交于 2019-12-20 03:30:13

问题


Oi!

I'm having issues serializing my session state. We have 2 components, our WCF and Web. Based on our AdministrationPartial.cs and Administration.svc we generate "Administration.cs" code for our web project with the following .bat file :

svcutil.exe http://wcf_url.local/Administration.svc?wsdl /r:"{Path}\{Namespace}.dll" /d:"{Path}\{Namespace}\Code"

I removed the personal data from the above statement and replaced it with {path} and {namespace}. The Administration.cs will be inside the Code map.

In the Partial we have :

[Serializable]
public partial class MyObject
{
    <Some code>
}

It generated the following code :

namespace {mynamespace}
{
          using System.Runtime.Serialization

          [System.Diagnostics.DebuggerStepThroughAttribute()]
          [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
          [System.Runtime.Serialization.DataContractAttribute(Name="MyObject", Namespace="http://schemas.datacontract.org/2004/07/{namespace}")]
          public partial class MyObject : object, System.Runtime.Serialization.IExtensibleDataObject
          {
                    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
                    ...... generated code

What am i doing wrong?

Tim

EDIT : Actual error is : Type 'System.Runtime.Serialization.ExtensionDataObject' in Assembly 'System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.


回答1:


It appears that your question is, How can I create a class that is [Serializable] for BinaryFormatter and also implements IExtensibleDataObject for DataContractSerializer?

The answer is that this does not work out of the box since, as you have noticed, ExtensionDataObject is not marked as serializable. Nevertheless it can be done with a bit of extra coding. For whatever reason Microsoft chose to make ExtensionDataObject a completely opaque pointer, with no public properties or other ways to access the data therein. Except that it is possible to access the data inside by re-serializing to XML using DataContractSerializer. This suggests a way to make your MyObject class serializable: store the extension data in a proxy container field that implements ISerializable and, internally, serializes and deserializes the extension data to XML.

The following proxy wrapper accomplishes this task:

[Serializable]
public struct ExtensionDataObjectSerializationProxy : ISerializable
{
    public static implicit operator ExtensionDataObjectSerializationProxy(ExtensionDataObject data) { return new ExtensionDataObjectSerializationProxy(data); }

    public static implicit operator ExtensionDataObject(ExtensionDataObjectSerializationProxy proxy) { return proxy.ExtensionData; }

    private readonly System.Runtime.Serialization.ExtensionDataObject extensionDataField;

    public ExtensionDataObject ExtensionData { get { return extensionDataField; } }

    [DataContract(Name = "ExtensionData", Namespace = "")]
    sealed class ExtensionDataObjectSerializationContractProxy : IExtensibleDataObject
    {
        private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

        #region IExtensibleDataObject Members

        public ExtensionDataObject ExtensionData
        {
            get
            {
                return extensionDataField;
            }
            set
            {
                extensionDataField = value;
            }
        }

        #endregion
    }

    public ExtensionDataObjectSerializationProxy(ExtensionDataObject extensionData)
    {
        this.extensionDataField = extensionData;
    }

    public ExtensionDataObjectSerializationProxy(SerializationInfo info, StreamingContext context)
    {
        var xml = (string)info.GetValue("ExtensionData", typeof(string));
        if (!string.IsNullOrEmpty(xml))
        {
            var wrapper = DataContractSerializerHelper.LoadFromXML<ExtensionDataObjectSerializationContractProxy>(xml);
            extensionDataField = (wrapper == null ? null : wrapper.ExtensionData);
        }
        else
        {
            extensionDataField = null;
        }
    }

    #region ISerializable Members

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {
        if (ExtensionData != null)
        {
            var xml = DataContractSerializerHelper.GetXml(new ExtensionDataObjectSerializationContractProxy { ExtensionData = this.ExtensionData });
            info.AddValue("ExtensionData", xml);
        }
        else
        {
            info.AddValue("ExtensionData", (string)null);
        }
    }

    #endregion
}

public static class DataContractSerializerHelper
{
    public static string GetXml<T>(T obj, DataContractSerializer serializer = null)
    {
        using (var textWriter = new StringWriter())
        {
            using (var xmlWriter = XmlWriter.Create(textWriter))
            {
                (serializer ?? new DataContractSerializer(typeof(T))).WriteObject(xmlWriter, obj);
            }
            return textWriter.ToString();
        }
    }

    public static T LoadFromXML<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);
        }
    }
}

Then manually modify your MyObject class as follows:

public partial class MyObject : object, System.Runtime.Serialization.IExtensibleDataObject
{
    private ExtensionDataObjectSerializationProxy extensionDataField; // Use the proxy not ExtensionDataObject directly

    public ExtensionDataObject ExtensionData
    {
        get
        {
            return extensionDataField;
        }
        set
        {
            extensionDataField = value;
        }
    }
}



回答2:


Simpler answer see: http://blogs.msdn.com/b/mohamedg/archive/2010/02/15/extensiondataobject-is-not-marked-as-serializable.aspx

Just mark the private ExtensionDataObject as non serialized:

[NonSerialized]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;


来源:https://stackoverflow.com/questions/32056762/extensiondataobject-not-marked-as-serializable

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