John Russell
John Russell

Reputation: 2247

EF DataContractSerializer Exception

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

Answers (1)

tec-goblin
tec-goblin

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

Related Questions