问题
Oi!
I'm having issues serializing my session state. We have 2 components, our WCF and Web. Based on our AdministrationPartial.cs and Administration.svc we generate "Administration.cs" code for our web project with the following .bat file :
svcutil.exe http://wcf_url.local/Administration.svc?wsdl /r:"{Path}\{Namespace}.dll" /d:"{Path}\{Namespace}\Code"
I removed the personal data from the above statement and replaced it with {path} and {namespace}. The Administration.cs will be inside the Code map.
In the Partial we have :
[Serializable]
public partial class MyObject
{
<Some code>
}
It generated the following 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
What am i doing wrong?
Tim
EDIT : Actual error is : Type 'System.Runtime.Serialization.ExtensionDataObject' in Assembly 'System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.
回答1:
It appears that your question is, How can I create a class that is [Serializable] for BinaryFormatter and also implements IExtensibleDataObject for DataContractSerializer?
The answer is that this does not work out of the box since, as you have noticed, 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 and, internally, serializes and deserializes the extension data to XML.
The following proxy wrapper accomplishes this task:
[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);
}
}
}
Then manually modify your MyObject class as follows:
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;
}
}
}
回答2:
Simpler answer see: http://blogs.msdn.com/b/mohamedg/archive/2010/02/15/extensiondataobject-is-not-marked-as-serializable.aspx
Just mark the private ExtensionDataObject as non serialized:
[NonSerialized]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
来源:https://stackoverflow.com/questions/32056762/extensiondataobject-not-marked-as-serializable