In this blog post I will show how to implement a custom XmlMediaTypeFormatter that extends the default ASP.NET Web API XmlMediaTypeFormatter in a way that it ignores XML namespaces when parsing xml messages.

By default the ASP.NET Web API
XmlMediaTypeFormatter is not able to parse XML requests that contain any XML namespace declarations. If you would like to support clients, that (for any reason) send messages containing XML namespaces you can use the IgnoreNamespacesXmlMediaTypeFormatter that is defined as follows:

public
class IgnoreNamespacesXmlMediaTypeFormatter : XmlMediaTypeFormatter
{

  // See http://wiki.tei-c.org/index.php/Remove-Namespaces.xsl
  private const string NamespaceRemover =
    @"<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
        <xsl:output method='xml' indent='no'/>
        <xsl:template match='/|comment()|processing-instruction()'>
          <xsl:copy>
            <xsl:apply-templates/>
          </xsl:copy>
        </xsl:template>
        <xsl:template match='*'>
          <xsl:element name='{local-name()}'>
            <xsl:apply-templates select='@*|node()'/>
          </xsl:element>
        </xsl:template>
        <xsl:template match='@*'>
          <xsl:attribute name='{local-name()}'>
            <xsl:value-of select='.'/>
          </xsl:attribute>
        </xsl:template>
      </xsl:stylesheet>";

  private readonly XslCompiledTransform _xlstTransformer;

  public IgnoreNamespacesXmlMediaTypeFormatter()
  {
    var xslt = XDocument.Parse(NamespaceRemover, LoadOptions.PreserveWhitespace);
    _xlstTransformer = new XslCompiledTransform();
    _xlstTransformer.Load(xslt.CreateReader(), new XsltSettings(), new XmlUrlResolver());
  }

  public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
  {
    try
    {
      // Read XML
      var xmlDocument = XDocument.Load(new XmlTextReader(stream));

      // Transform XML
      var resultStream = new MemoryStream();
      _xlstTransformer.Transform(xmlDocument.CreateReader(), XmlWriter.Create(resultStream, new XmlWriterSettings() { OmitXmlDeclaration = true }));
      resultStream.Position = 0;

      // Process request with XmlMediaTypeFormatter default functionality
      return base.ReadFromStreamAsync(type, resultStream, contentHeaders, formatterLogger);
    }
    catch (XmlException)
    {
      return base.ReadFromStreamAsync(type, stream, contentHeaders, formatterLogger);
    }
  }
}


In detail the
IgnoreNamespacesXmlMediaTypeFormatter removes the XML namespace declarations from the XML message and passes the modified XML to the base class to use the default XmlMediaTypeFormatter functionality. Removing the XML namespaces is done with a XSLT transformation (see http://wiki.tei-c.org/index.php/Remove-Namespaces.xsl).

To activate the
IgnoreNamespacesXmlMediaTypeFormatter add the following lines in the file Global.asax.cs:

protected
void Application_Start()
{

  [...]
  // Remove default XmlFormatter and add (customized) IgnoreNamespacesXmlMediaTypeFormatter

GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

  var ignoreNamespacesXmlMediaTypeFormatter = new IgnoreNamespacesXmlMediaTypeFormatter{ UseXmlSerializer = true };

GlobalConfiguration.Configuration.Formatters.Add(ignoreNamespacesXmlMediaTypeFormatter);

  [...]
}