使用 XmlDocument 属性 序列化对象
serialize object with XmlDocument Property
我有很多 class 包含一些字段和类型 XmlDocument
的属性。
当我把这些classes的对象放到session中时(比如stateServer,SQLStateServer)需要序列化。
但是如果我们有一个 XmlDocument 类型的 属性 并在我们的 class 上面添加 [Serialize]
属性,就会出现以下错误。
Unable to serialize the session state. In 'StateServer' and
'SQLServer' mode, ASP.NET will serialize the session state objects,
and as a result non-serializable objects or MarshalByRef objects are
not permitted. The same restriction applies if similar serialization
is done by the custom session state store in 'Custom' mode.
对于具有 [NonSerialize]
属性的字段,不会出现此错误。属性不能具有 [NonSerialize]
属性,因为它只能用于 class 和结构、事件和委托。
在内部,根据docs, the state server uses BinaryFormatter
to serialize complex types. BinaryFormatter
serializes all public and private fields (not properties!) of a class or struct that is marked as [Serializable]
. But XmlDocument
,正如你所注意到的,没有那么标记,因此不能立即用BinaryFormatter
序列化。
然而,XmlDocument
可以简单地转换为字符串——文档表示的 XML 本身。因此,如果 XmlDocument
字段包含在实现 ISerializable
, then its GetObjectData()
的类型中,则可以简单地将相应的 XML 字符串存储在序列化流中。然后相应的序列化构造函数可以提取 XML 字符串并重构 XmlDocument
.
由于在预先存在的 class 上实现 ISerializable
可能很耗时,因此实现您想要的最简单方法是为您的 [=37= 引入一个小型序列化包装器结构] 文件:
[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
}
然后,在要序列化的 classes 中,用包装器结构字段替换 XmlDocument
字段(和自动实现的属性),例如:
[Serializable]
public class TestClass
{
XmlDocumentSerializationWrapper doc;
public XmlDocument Document { get { return doc; } set { doc = value; } }
}
结构中的隐式运算符处理与包装器之间的自动转换。
我有很多 class 包含一些字段和类型 XmlDocument
的属性。
当我把这些classes的对象放到session中时(比如stateServer,SQLStateServer)需要序列化。
但是如果我们有一个 XmlDocument 类型的 属性 并在我们的 class 上面添加 [Serialize]
属性,就会出现以下错误。
Unable to serialize the session state. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as a result non-serializable objects or MarshalByRef objects are not permitted. The same restriction applies if similar serialization is done by the custom session state store in 'Custom' mode.
对于具有 [NonSerialize]
属性的字段,不会出现此错误。属性不能具有 [NonSerialize]
属性,因为它只能用于 class 和结构、事件和委托。
在内部,根据docs, the state server uses BinaryFormatter
to serialize complex types. BinaryFormatter
serializes all public and private fields (not properties!) of a class or struct that is marked as [Serializable]
. But XmlDocument
,正如你所注意到的,没有那么标记,因此不能立即用BinaryFormatter
序列化。
XmlDocument
可以简单地转换为字符串——文档表示的 XML 本身。因此,如果 XmlDocument
字段包含在实现 ISerializable
, then its GetObjectData()
的类型中,则可以简单地将相应的 XML 字符串存储在序列化流中。然后相应的序列化构造函数可以提取 XML 字符串并重构 XmlDocument
.
由于在预先存在的 class 上实现 ISerializable
可能很耗时,因此实现您想要的最简单方法是为您的 [=37= 引入一个小型序列化包装器结构] 文件:
[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
}
然后,在要序列化的 classes 中,用包装器结构字段替换 XmlDocument
字段(和自动实现的属性),例如:
[Serializable]
public class TestClass
{
XmlDocumentSerializationWrapper doc;
public XmlDocument Document { get { return doc; } set { doc = value; } }
}
结构中的隐式运算符处理与包装器之间的自动转换。