Сериализация объекта с помощью свойства XmlDocument

У меня есть много классов, которые содержат некоторые поля и свойства типа XmlDocument, Когда я помещаю объекты этих классов в сессию (например, State Server, SQL State Server), необходимо их сериализовать. Но если у нас есть свойство типа XmlDocument и добавить [Serialize] Атрибут выше нашего класса, появится следующая ошибка.

Невозможно сериализовать состояние сеанса. В режимах "StateServer" и "SQLServer" ASP.NET сериализует объекты состояния сеанса, и в результате несериализуемые объекты или объекты MarshalByRef не допускаются. То же ограничение применяется, если аналогичная сериализация выполняется в пользовательском хранилище состояний сеанса в режиме "Пользовательский".

эта ошибка не отображается для полей [NonSerialize] приписывать. свойства не могут иметь атрибут [NonSerialize] потому что это может использоваться только для класса и структуры и события и делегата.

1 ответ

Решение

Внутренне, в соответствии с документами, сервер состояний использует BinaryFormatter сериализовать сложные типы. BinaryFormatter сериализует все открытые и закрытые поля (не свойства!) класса или структуры, помеченных как [Serializable], Но XmlDocument, как вы заметили, не так помечены, поэтому не могут быть немедленно сериализованы с BinaryFormatter,

XmlDocument однако может быть легко преобразован из строки в строку - сам XML, который представляет документ. Таким образом, если XmlDocument поле содержалось в реализации типа ISerializable тогда его GetObjectData() может просто сохранить соответствующую строку XML внутри потока сериализации. Затем соответствующий конструктор сериализации может извлечь строку XML и восстановить XmlDocument,

С момента внедрения ISerializable в уже существующем классе может потребоваться много времени, самый простой способ выполнить то, что вы хотите, - это ввести небольшую структуру-обертку сериализации для ваших XML-документов:

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

    public static implicit operator XmlDocument(XmlDocumentSerializationWrapper wrapper) { return wrapper.XmlDocument; }

    private readonly XmlDocument xmlDocument;

    public XmlDocument XmlDocument { get { return xmlDocument; } }

    public XmlDocumentSerializationWrapper(XmlDocument xmlDocument)
    {
        this.xmlDocument = xmlDocument;
    }

    public XmlDocumentSerializationWrapper(SerializationInfo info, StreamingContext context)
    {
        var xml = (string)info.GetValue("XmlDocument", typeof(string));
        if (!string.IsNullOrEmpty(xml))
        {
            xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(xml);
        }
        else
        {
            xmlDocument = null;
        }
    }

    #region ISerializable Members

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {
        if (XmlDocument != null)
        {
            var xml = XmlDocument.OuterXml;
            info.AddValue("XmlDocument", xml);
        }
        else
        {
            info.AddValue("XmlDocument", (string)null);
        }
    }

    #endregion
}

Затем в классах, которые вы хотите сериализовать, замените XmlDocument поля (и автоматически реализуемые свойства) с полями структуры оболочки, например:

[Serializable]
public class TestClass
{
    XmlDocumentSerializationWrapper doc;

    public XmlDocument Document { get { return doc; } set { doc = value; } }
}

Неявные операторы в структуре обрабатывают автоматическое преобразование из и в оболочку.

Другие вопросы по тегам