XML model binding fails in ASP.net WebApi2 after a time
I have several webapi micro services hosted in TopShelf containers which accept and reply with JSON and XML formatters. After running for a time, the XML formatter stops binding the XML request data to the model. Passing JSON or Form-Data still works . Specifying an Accept: application/xml
header which results in an XML response. Replaying the failed XML requests after restarting the service returns the expected responses .
The root cause of the problem is that the SupportedMediaTypes
property of the XmlFormatter gets cleared at some point while the service is running and the model binding fails.
How can I find what is clearing the SupportedMediaTypes
?
Notes while investigating the problem follow.
I cannot replicate the problem in any environments which I can connect a debugger to.
One of the services started failing while I was debugging locally. From what I can see, it is picking the DataContractSerializer rather than the XmlSerializer for deserialization.
The Startup class adds the formatters in this order:
config.Formatters.Clear();
config.Formatters.Add(new RecordSetMediaTypeFormatter<RecordAssociation>());
config.Formatters.Add(new XmlMediaTypeFormatter { UseXmlSerializer = true });
config.Formatters.Add(new XmlMediaTypeFormatter { UseXmlSerializer = false });
config.Formatters.Add(new JsonMediaTypeFormatter());
Checking the formatter order in HttpConfiguration shows that the XmlSerializer formatter has priority:
> actionContext.RequestContext.Configuration.Formatters
Count = 4
[0]: {API.Formatters.RecordSetMediaTypeFormatter<API.Contract.DataObjects.RecordAssociation>}
[1]: {System.Net.Http.Formatting.XmlMediaTypeFormatter}
[2]: {System.Net.Http.Formatting.XmlMediaTypeFormatter}
[3]: {System.Net.Http.Formatting.JsonMediaTypeFormatter}
> (actionContext.RequestContext.Configuration.Formatters[1] as System.Net.Http.Formatting.XmlMediaTypeFormatter).UseXmlSerializer
true
> (actionContext.RequestContext.Configuration.Formatters[2] as System.Net.Http.Formatting.XmlMediaTypeFormatter).UseXmlSerializer
false
The UseXmlSerializer == true
formatter indicates that it can read the type, but the UseXmlSerializer == false
formatter is selected by the collection, even with System.Object
:
> actionContext.RequestContext.Configuration.Formatters[1].CanReadType(typeof(System.Object))
true
> (actionContext.RequestContext.Configuration.Formatters.FindReader(typeof(System.Object), System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/xml")) as System.Net.Http.Formatting.XmlMediaTypeFormatter).UseXmlSerializer
false
Why does the MediaTypeFormatterCollection.FindReader
method return the lower priority formatter?
Checking the source for MediaTypeFormatterCollection
on GitHub (thanks Microsoft!), I thought to look at the SupportedMediaTypes
for both instances:
> actionContext.RequestContext.Configuration.Formatters[1].SupportedMediaTypes
Count = 0
> actionContext.RequestContext.Configuration.Formatters[2].SupportedMediaTypes
Count = 2
[0]: {application/xml}
[1]: {text/xml}
On a restart of the project, the collection for Formatters[1] is the same as for Formatters[2].
The only references to the MediaTypeFormatter.SupportedMediaTypes
property in the project is where the RecordSetMediaTypeFormatter
sets its own SupportedMediaTypes
in its constructor.
What is clearing the XmlFormatter's SupportedMediaTypes
property at run-time?