12

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?

psaxton
  • 1,693
  • 19
  • 24
  • Hi, were you able to find the what was the issue here. Want to know why two formatters of same type with true/false values were added – NitinSingh May 23 '18 at 06:26
  • I believe I eventually traced the problem to a third party library cleared the property when a particular class was loaded. I just used a different library for that functionality. I'll have to check source control when I get a chance to see if I can find what the library was. – psaxton May 23 '18 at 14:33

0 Answers0