1

我有很多类,其中包含一些类型的字段和属性XmlDocument。当我把这些类的对象放在会话中时(比如状态服务器、SQL 状态服务器),就需要对它们进行序列化。但是如果我们有一个 XmlDocument 类型的属性并 [Serialize]在我们的类上方添加 Attribute ,就会出现以下错误。

无法序列化会话状态。在“StateServer”和“SQLServer”模式下,ASP.NET 将序列化会话状态对象,因此不允许不可序列化的对象或 MarshalByRef 对象。如果自定义会话状态存储在“自定义”模式下完成类似的序列化,则适用相同的限制。

[NonSerialize]对于具有属性的字段,不会出现此错误。属性不能具有属性[NonSerialize],因为它只能用于类和结构以及事件和委托。

4

1 回答 1

2

在内部,根据文档,状态服务器用于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; } }
}

结构中的隐式运算符处理与包装器之间的自动转换。

于 2015-09-15T10:05:02.770 回答