Santi
Santi

Reputation: 11

Using custom XmlMediaTypeFormatter to remove all namespaces in web api response c# .net

I am running into a problem trying to remove all namespaces in my XML Web Api response. In particular I am having trouble removing nested/children namespaces. I will start out with some background. I have a many model classes which I have decorated with

[XmlRoot("someRoot", Namespace = "someNameSpace")]

There are no other decorations in any of these classes just XmlRoots, perhaps this is not the nest approach?

Anyways,

I have implemented my own custom XmlMediaTypeFormatter by reading some of the answers in different forms here. The implementation is as follows (from Remove namespace in XML from ASP.NET Web API)

public class CustomNamespaceXmlFormatter : XmlMediaTypeFormatter
{
    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
                                            TransportContext transportContext)
    {
        try
        {
            var xns = new XmlSerializerNamespaces();
            foreach (var attribute in type.GetCustomAttributes(true))
            {
                var xmlRootAttribute = attribute as XmlRootAttribute;
                if (xmlRootAttribute != null)
                {
                    xns.Add(string.Empty, xmlRootAttribute.Namespace);
                }
            }

            if (xns.Count == 0)
            {
                xns.Add(string.Empty, string.Empty);
            }

            var task = Task.Factory.StartNew(() =>
                {
                    var serializer = new XmlSerializer(type);
                    serializer.Serialize(writeStream, value, xns);
                });

            return task;
        }
        catch (Exception)
        {
            return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
        }
    }
}

I have also registered this in my WebApiConfig.cs as:

GlobalConfiguration.Configuration.Formatters.Add(new CustomNamespaceXmlFormatter());

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

Now my issue is that the namespaces are removed but there is some weird behavior in that they are now being added to their children...

For example, without the custom formatter my xml looks like

<d2p1:MyClass xmlns:d3p1="http://schemas.datacontract.org/2004/07/MyClass">
      <d3p1:ChildNodeOfMyClass>

But when using my CustomNamespaceXmlFormatter, I would get

<MyClass>
  <ChildNodeOfMyClass xmlns="http://schemas.datacontract.org/2004/07/MyClass">

This behavior occurs all throughout my response. Any ideas on why this is happening?

As a side note I would like to add that the reason I used XmlRoot is because some of my classes contain public attributes that have the same class name and is needed so that there is no conflict when serializing my response.

Any help/direction on how to handle this would be appreciated, thank you =)

Upvotes: 0

Views: 2444

Answers (1)

Santi
Santi

Reputation: 11

For anyone else that is looking to do something similar, I figured out one possible solution. This requires you to have Newtonsoft.Json as a reference in order to execute JsonConvert.DeserializeXmlNode(). The second parameter to this function is the name of your root node if you have multiple JSON root elements.

For reference into this method implentation: http://techqa.info/programming/question/17526299/Right-way-of-implementing-MediaTypeFormatter-WriteToStreamAsync-in-Web-API

public class CustomNamespaceXmlFormatter : XmlMediaTypeFormatter
{

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
                                            TransportContext transportContext)
    {
        try
        {
            XmlDocument doc = JsonConvert.DeserializeXmlNode(value.ToString(), "myRootElement");
            doc.LoadXml(doc.InnerXml);
            doc.Save(writeStream);
            var tcs = new TaskCompletionSource<object>();
            tcs.SetResult(null);
            return tcs.Task;
        }
        catch (Exception)
        {
            return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
        }
    }
}

Upvotes: 1

Related Questions