Reputation: 2247
I've hit a very interesting exception while trying to serialize a graph of EF 4 STEs.
System.IndexOutOfRangeException was caught
Message=Index was outside the bounds of the array.
Source=mscorlib
StackTrace:
Server stack trace:
at System.Runtime.Serialization.ObjectReferenceStack.EnsureSetAsIsReference(Object obj)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.OnHandleIsReference(XmlWriterDelegator xmlWriter, DataContract contract, Object obj)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
...
at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(Stream stream, Object graph)
My serialization code is fairly simple:
using (MemoryStream memoryStream = new MemoryStream())
{
DataContractSerializer dc = new DataContractSerializer(data.GetType());
dc.WriteObject(memoryStream, data);
memoryStream.Flush();
memoryStream.Position = 0;
StreamReader reader = new StreamReader(memoryStream);
var serializedObject = reader.ReadToEnd();
}
In my object graph, I've added a few child entities to a parent entity, and I've discovered that if I call the .AcceptChanges() extension method on the parent, everything serializes just fine.
Has anyone else encountered something like this? What could be causing it? Any ideas on how I can run down the culprit?
Update: I found a link where someone else had a similar problem. They said that System.Runtime.Serialization.ObjectReferenceStack.EnsureSetAsIsReference) is doing some cycle validation and could be finding a problem.
Update 2: I also found that setting preserveObjectReferences to true in the constructor for the DataContractSerializer clears up the exception.
Update 3: Ended up using approach described in this article to call overloaded DataContractSerializer constructor with preserveObjectReferences set to true. This fixed the issue, although I still can't explain it...
So maybe now, my question becomes: How is preserveObjectReferences on the DataContractSerializer different than having [DataContract(IsReference = true)] on all of the STE's?
Thanks!
Upvotes: 2
Views: 903
Reputation: 316
It seems PreserveObjectReferences uses "non-standard XML constructs" for all your classes, while isReference is the standard SOAP way, but it needs to be declared on every class where it is needed. I had the same problem and it was because I had missed putting it on some classes. The common trap is that DataContractAttribute is not inherited, so you have to redeclare it (with IsReference=true) for each inherited class.
Upvotes: 1