ExtensionDataObject 未标记为可序列化
ExtensionDataObject not marked as serializable
喂!
我在序列化会话状态时遇到问题。我们有 2 个组件,我们的 WCF 和 Web。基于我们的 AdministrationPartial.cs 和 Administration.svc,我们使用以下 .bat 文件为我们的 Web 项目生成 "Administration.cs" 代码:
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.
看来您的问题是,我怎样才能为 BinaryFormatter
创建 [Serializable]
的 class 并为 [ 实现 IExtensibleDataObject
=15=]?
答案是这不是开箱即用的,因为正如您所注意到的,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
并且在内部将扩展数据序列化和反序列化为 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
class如下:
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;
}
}
}
只需将私有 ExtensionDataObject 标记为非序列化:
[NonSerialized]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
喂!
我在序列化会话状态时遇到问题。我们有 2 个组件,我们的 WCF 和 Web。基于我们的 AdministrationPartial.cs 和 Administration.svc,我们使用以下 .bat 文件为我们的 Web 项目生成 "Administration.cs" 代码:
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.
看来您的问题是,我怎样才能为 BinaryFormatter
创建 [Serializable]
的 class 并为 [ 实现 IExtensibleDataObject
=15=]?
答案是这不是开箱即用的,因为正如您所注意到的,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
并且在内部将扩展数据序列化和反序列化为 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
class如下:
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;
}
}
}
只需将私有 ExtensionDataObject 标记为非序列化:
[NonSerialized]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;