Skip to content

Instantly share code, notes, and snippets.

@shmuelie
Created April 20, 2016 14:33
Show Gist options
  • Save shmuelie/978742401960aae3eaa7e95a27c0d63b to your computer and use it in GitHub Desktop.
Save shmuelie/978742401960aae3eaa7e95a27c0d63b to your computer and use it in GitHub Desktop.
System.Xml.Serialization.XmlSerializer Limitations in .NET Core

(Note: Code is using .NET Core and ASP.NET Core that is in VS 2015 Update 2)

When you want to return XML in ASP.NET Core the Microsoft.AspNet.Mvc.Formatters.XmlSerializerOutputFormatter is used. Internally XmlSerializerOutputFormatter uses System.Xml.Serialization.XmlSerializer to actually serialize the .NET Objects into XML. Unfortunaly XmlSerializer has some limitations, particularly around serializing collections. To solve this a concept of "wrappers" was introduced. Wrappers replace an object of type A with type AWrap and AWrap provides all the same data but is XmlSerializer safe. ASP.NET Core comes with a wrapper for collections built in. However, to use it you must write you own wrappers for your classes that consume it when they have collections.

Instead of creating wrappers for a complex and growing object model, I created a system that uses type generation at runtime to create wrappers for types as needed. Unfortunately some limitations in .NET Core made this more complex then something similar in .NET Framework would have been.

The first issue is that in .NET Core assemblies created at runtime cannot be saved to disk. This causes issues when XmlSerializer looks for the assembly to do reflection for serialization. It is unable to find the assembly and crashes. To solve this in .NET Framework I would handle the System.AppDomain.AssemblyResolve event. In .NET Core System.AppDomain is internal to the framework and there is not clear or good replacement yet. Once this problem is solved, the next issue is that the native way that .NET Core tries to read custom attributes of classes using native code does not work on dynamically created assemblies. So when the XmlSerializer tries to read the attributes that help it decided how to serialize the objects and their properties it crashes. This once again should be solved by simply saving the assembly to disk but that cannot be done in .NET Core.

To deal with the failure to find the dynamic assembly for reflection I used reflection to get the internal System.AppDomain and handle the hidden AssemblyResolve event (I also handle the TypeResolve event to be safe). To deal with the attribute reading, I create a System.Xml.Serialization.XmlAttributeOverrides instance that I fill with the attributes that I manually reflect over my types with. I then created a class that inherits from Microsoft.AspNet.Mvc.Formatters.XmlSerializerOutputFormatter and overrides the CreateSerializer method. In there I pass the XmlAttributeOverrides instance in. By doing these two things I have overcome the limitations of the .NET Core and allowed me to overcome the limitations of XmlSerializer.

@terrajobst
Copy link

Is there any reason why these assemblies have to be generated using ref emit? For instance, how about generating them using Roslyn?

@shmuelie
Copy link
Author

shmuelie commented May 2, 2016

In theory you could use Roslyn to create them but last I checked Roslyn can't reflect over the existing assembly?

@smithaitufe
Copy link

Please what is the state with serialization now in aspnet core? I am having errors while to serialize object to xml. It is not able to reflect the different types especially nested ones.

Do you have a way to get out this problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment