In one of my last projects, where Microsoft .NET assemblies can be updated at runtime, sometimes we ran into an exception, “There is an error in XML document”. Even when nothing changed in reference to any part of the code dealing with the object being serialized, or the serialization code itself we would see this error.
I sat down to try and figure out why.
The exception was happening inside the Microsoft generated dynamic dlls for XmlSerialization. You can get the dll to stick around if you follow Hanselman’s instructions. Once we can step into the DLLs we see the error is happening on a line like this
if ((object)(a_0_0) == null) Reader.Skip(); else method9_Add.Invoke( ...
The error is a null reference exception because method9_Add is null. So looking at what method9_Add actually is:
System.Reflection.MethodInfo method9_Add = type2_Item.GetMethod("Add" ...
So they are using reflection. The method they are trying to get is the Add method on a generic dictionary. In particular for they are trying to get the Add method for a List<MyBizObject>. This fails because GetMethod’s execution context doesn’t know anything about MyBizObject.
This begs the question as to why it works normally. Doing the same steps without updating the dll at runtime:
if ((object)(a_0_0) == null) Reader.Skip(); else a_0_0.Add( ...
Ah ha! Normally XmlSerialization doesn’t use reflection, a_0_0 is a real object. After doing some digging in reflector we find.
A null assembly.Location will mark the type as dynamic and a dynamic assembly triggers XmlSerialization to generate reflection members. When a DLL is loaded with using Assembly.Load assembly.Location to be an empty string. Causing our issue.
In this particular case the fix was to stop using a strongly typed List<MyBizObject> and just use an ArrayList. This way the reflection code generated by Microsoft worked fine.
Maybe we should use temp files and shadow loading instead of loading from byte[]?