locked
Possible bug in DataContract / Serialization engine RRS feed

  • Question

  • Hello

    I think I've stumbled across another bug. I receive a SecurityException when trying to serialize some types. I think its a bug because no one else in the world seems to have encountered this problem - the pertinent method names in the callstack get no Google hits.

    This is not a problem with KnownTypes. If I remove the code that registers the types, it throws a different (correct) error to do with unexpected types. The code serializes some generic caches containing more generic objects. This works well and dandy for some pretty complicated caches but just bails on some others. I cannot find a pattern. The types are received from a WCF service, so they serialize OK.

    I've tried JSON and XML, the code failing seems to be deeper/shared. The annoying thing is that this is deep within the architecture of my app so it will mean some significant work to change the way my app works.

    The really odd thing is that the ValidateSecurity method doesn't exist on the DataContract type when I use the Reflector to take a look at what might be happening. The other methods do exist.


       at System.Runtime.Serialization.DataContract.ValidateSecurity(MemberInfo member)
       at System.Runtime.Serialization.DataContract.IsTypeVisible(Type t, Assembly[] serializationAssemblies)
       at System.Runtime.Serialization.DataContract.IsTypeAccessible(Type type)
       at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
       at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.GetDataContract(Type type)
       at System.Runtime.Serialization.ClassDataContract.ClassDataContractCriticalHelper..ctor(Type type)
       at System.Runtime.Serialization.ClassDataContract..ctor(Type type)
       at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
       at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.GetDataContract(Type type)
       at System.Runtime.Serialization.DataContract.CheckAndAdd(Type type, Dictionary`2 typesChecked, Dictionary`2& nameToDataContractTable)
       at System.Runtime.Serialization.XmlObjectSerializerContext.GetDataContractsForKnownTypes(IList`1 knownTypeList)
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.get_KnownDataContracts()
       at System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson..ctor(DataContractJsonSerializer serializer, DataContract rootTypeDataContract)
       at System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson.CreateContext(DataContractJsonSerializer serializer, DataContract rootTypeDataContract)
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(Stream stream, Object graph)
       at Evoq.Vuplan.Mobile.Data.DataContractSerializerHelper.SerializeToJson(Object serializable, Stream stream)
       at Evoq.Vuplan.Mobile.Data.DataContractSerializerHelper.SerializeToJson(Object serializable, String& xml)
       at Evoq.Vuplan.Mobile.Data.PersistableCacheContainer.PersistCache(String name)
       at Evoq.Vuplan.Mobile.Data.PersistableCacheContainer.PersistCaches()
       at Evoq.Vuplan.Mobile.Data.PersistableCacheContainer.PersistableCacheContainer_Navigating(Object sender, NavigatingCancelEventArgs e)
       at System.Windows.Navigation.NavigationService.RaiseNavigating(Uri uri, NavigationMode mode, Boolean isFragmentNavigationOnly, PhoneApplicationPage existingContentPage)
       at System.Windows.Navigation.NavigationService.Journal_NavigatingBack(Object sender, JournalEventArgs args)
       at System.Windows.Navigation.Journal.OnNavigatingBack()
       at System.Windows.Navigation.Journal.ShellPage_BackKeyPressed(Object sender, BackKeyPressEventArgs args)
       at Microsoft.Phone.Shell.Interop.ShellPageCallback.FireOnBackKeyPress(IntPtr pageThis)



    Thanks!


    UPDATE 1 - Thursday 14 July

    The following shows that the type that fails serialization is the KeyValuePair<object, object> which contains types key = String and value = CachedItem<Collection<ProfileGroup>>> both of which serialize individually. For example:

                        DataContractSerializerHelper.Serialize(ssc.HotBucket.First().Value, out sz);
                        DataContractSerializerHelper.Serialize(ssc.HotBucket.First().Key, out sz);
                        DataContractSerializerHelper.Serialize(ssc.HotBucket.First(), out sz); // Fails here.
                        DataContractSerializerHelper.Serialize(ssc.HotBucket , out sz);
                        DataContractSerializerHelper.Serialize(ssc, out sz);

    So the its not a problem actually serializing the data, the first two lines above work fine, its something to do with the pair.

    UPDATE 2 - Thursday 14 July

    If I create my own tuple type to replace the KeyValuePair, I get the same problem. I wonder if I'm obscuring the resolution of the correct data contract somehow with this extra layer.

    UPDATE 3 - Thursday 14 July

    I have worked around the issue by storing the Key on the Value, i.e. added a Key property to the Value type (which is CachedItem<T>) and then changing HotBucket to a collection of CachedItem<T> instead of pairs. This adds another step to deserialization; I must 'manually' recreate the HotBucket dictionary entries after [successful] deserialization with a simple HotBucket.Add(cachedItem.Key, cachedItem);

    UPDATE 4 - Sunday 17 July

    I am now seeing a common InvalidOperationException when serializing some objects. Some of the objects serialize fine, some don't. Here's the error message and stack trace:

    "Token StartElement in state EndRootElement would result in an invalid XML document. Make sure that the ConformanceLevel setting is set to ConformanceLevel.Fragment or ConformanceLevel.Auto if you want to write an XML fragment. "

       at System.Xml.XmlWellFormedWriter.ThrowInvalidStateTransition(Token token, State currentState)
       at System.Xml.XmlWellFormedWriter.AdvanceState(Token token)
       at System.Xml.XmlWellFormedWriter.WriteStartElement(String prefix, String localName, String ns)
       at System.Xml.XmlDictionaryWriter.XmlWrappedWriter.WriteStartElement(String prefix, String localName, String namespaceUri)
       at System.Xml.XmlDictionaryWriter.WriteStartElement(String prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri)
       at System.Runtime.Serialization.XmlWriterDelegator.WriteStartElementPrimitive(XmlDictionaryString localName, XmlDictionaryString namespaceUri)
       at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteString(XmlWriterDelegator xmlWriter, String value, XmlDictionaryString name, XmlDictionaryString ns)
       at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)
       at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
       at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
       at System.Runtime.Serialization.XmlFormatWriter.TryWritePrimitive(Type type, Object value, MemberInfo memberInfo, Int32 arrayItemIndex, XmlDictionaryString ns, XmlDictionaryString name, Int32 nameIndex, XmlDictionaryString[] memberNames, Object& objectLocal, DataContract contract, XmlObjectSerializerWriteContext context, XmlWriterDelegator xmlWriter)
       at System.Runtime.Serialization.XmlFormatWriter.WriteMember(SerializingObject serObj, Int32 memberIndex, ClassDataContract derivedMostClassContract)
       at System.Runtime.Serialization.XmlFormatWriter.WriteClass(CallStackElement`1 callStackElement)
       at System.Runtime.Serialization.XmlFormatWriter.Serialize(XmlObjectSerializerWriteContext context)
       at System.Runtime.Serialization.XmlFormatWriter.InitializeCallStack(XmlWriterDelegator xmlWriterDel, Object obj, XmlObjectSerializerWriteContext writeContext, DataContract contract)
       at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
       at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
       at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
       at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph)
       at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph)
       at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph)
       at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
       at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(Stream stream, Object graph)
       at Evoq.Vuplan.Mobile.Data.DataContractSerializerHelper.Serialize(Object serializable, Stream stream)
       at Evoq.Vuplan.Mobile.Data.DataContractSerializerHelper.Serialize(Object serializable, String& xml)
       at Evoq.Vuplan.Mobile.Data.PersistableCacheContainer.PersistCache(String name)
       at Evoq.Vuplan.Mobile.Data.PersistableCacheContainer.<PersistCachesAsync>b__2()
       at Evoq.Vuplan.Mobile.Execution.SimpleAsyncTask`1.<>c__DisplayClass1.<QueueWorkForImmediateAsynch>b__0(Object )
       at System.Threading.ThreadPool.WorkItem.doWork(Object o)
       at System.Threading.Timer.ring()


    UPDATE 4 - Sunday 17 July

    I was able to solve the above by adding a lock for access to the DataContractSerializer (even though its a new instance on each use). There seems to be some shared state in the DCS that means when multiple threads are serializing objects, they get confused and fall over.

    Wednesday, July 13, 2011 6:18 PM