(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
.
In theory you could use Roslyn to create them but last I checked Roslyn can't reflect over the existing assembly?