2

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.

dbc
  • 104,963
  • 20
  • 228
  • 340
Tim Ververs
  • 527
  • 9
  • 23
  • I'm not sure I understand your question. 1) Are you asking why Microsoft did not apply the `[Serializable]` attribute to the .Net type `ExtensionDataObject`? 2) Are you using both the data contract serializer and `BinaryFormatter` to serialize your class `MyObject`? – dbc Aug 17 '15 at 21:45
  • State the main issue you encounter. – jtabuloc Aug 18 '15 at 05:53
  • I encouter the following error : Type 'System.Runtime.Serialization.ExtensionDataObject' in Assembly 'System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable. – Tim Ververs Aug 19 '15 at 07:15
  • What are you doing when you encounter this error? Can you provide a [reproducible example](http://stackoverflow.com/help/mcve) that generates the error? (It looks as though you are doing binary serialization, is that correct?) – dbc Aug 19 '15 at 07:35
  • Is your question, "how can I serialize a class, using `BinaryFormatter`, that implements `IExtensibleDataObject` and contains a field of type `ExtensionDataObject`, when the latter is not marked as `[Serializable]`?" – dbc Aug 20 '15 at 07:08

2 Answers2

3

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;
        }
    }
}
dbc
  • 104,963
  • 20
  • 228
  • 340
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;
DOsborn
  • 21
  • 1