ExtensionDataObject не помечен как сериализуемый

Oi!

У меня проблемы с сериализацией моего состояния сеанса. У нас есть 2 компонента, наш WCF и веб. На основе наших AdministrationPartial.cs и Administration.svc мы генерируем код "Administration.cs" для нашего веб-проекта со следующим файлом.bat:

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

Я удалил личные данные из вышеприведенного заявления и заменил их {path} и ​​{namespace}. Administration.cs будет находиться внутри карты кода.

В Частичном мы имеем:

[Serializable]
public partial class MyObject
{
    <Some 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

Что я делаю неправильно?

Тим

РЕДАКТИРОВАТЬ: Фактическая ошибка: Type 'System.Runtime.Serialization.ExtensionDataObject' in Assembly 'System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.

2 ответа

Решение

Похоже, что ваш вопрос, как я могу создать класс, который [Serializable] заBinaryFormatterа также реализуетIExtensibleDataObjectза DataContractSerializer ?

Ответ заключается в том, что это не работает из коробки, так как, как вы заметили,ExtensionDataObjectне помечен как сериализуемый. Тем не менее, это может быть сделано с небольшим количеством дополнительного кодирования. По какой-то причине Microsoft решила сделать ExtensionDataObject полностью непрозрачный указатель, без открытых свойств или других способов доступа к данным в нем. За исключением того, что можно получить доступ к данным внутри путем повторной сериализации в XML с использованием DataContractSerializer, Это предлагает способ сделать вашMyObjectclass serializable: хранить данные расширения в поле прокси-контейнера, которое реализуетISerializable и внутренне сериализует и десериализует данные расширения в XML.

Следующая прокси-оболочка выполняет эту задачу:

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

Затем вручную измените ваш MyObject Класс следующим образом:

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

Более простой ответ см.: http://blogs.msdn.com/b/mohamedg/archive/2010/02/15/extensiondataobject-is-not-marked-as-serializable.aspx

Просто пометьте закрытый ExtensionDataObject как не сериализованный:

[NonSerialized]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
Другие вопросы по тегам