views:

2983

answers:

5

I am using WCF to return a plain old XML (POX) document to the caller. I am using the XML Serializer formatter to turn the objects into XML.

In the returned document I have some extraneous xml namespace references (that weren't there in the ASMX version) for the XML Schema and instance. I have seen various arguments on the web that these shouldn't be removed which I don't buy into for returning a plain XML document.

What is the simplest way of removing these xmlns references from a returned XML document in WCF?

The signature looks like:

public ResponseInfo Process(string input) {
}
A: 

In my RESTful WCF service which I wrote prior to the WCF RESTful starter kit I did the following which gives me nice, clean results.

First, make sure the webHttp endpoint behavior is set:

  <endpointBehaviors>
    <behavior name="Web">
      <webHttp/>
    </behavior>
  </endpointBehaviors>

Your endpoint should look something like this (minus the contract for simplicity):

<endpoint address="" binding="webHttpBinding" behaviorConfiguration="Web" />

My service contract has these operation contracts in it:

    [WebGet(UriTemplate="tasks", ResponseFormat=WebMessageFormat.Xml )]
    [OperationContract]
    Task[] GetTasks();

    [WebGet(UriTemplate="tasks/{id}", ResponseFormat=WebMessageFormat.Xml)]
    [OperationContract]
    Task GetTask(string id);

The service implementation itself has nothing special about it. You can try changing up the WebMessageFormat but the only other item in the enumeration is "json".

Sailing Judo
It would be nice if the downvoter would leave a comment. My answer is 100% correct and workable. It might not have fit exactly what the person asking needs, or perhaps there is a better way, but it certainly works.
Sailing Judo
+3  A: 

I assume you are trying instead of getting something like this at the beginning of your xml:

<ResponseInfo 
   xmlns="http://schemas.datacontract.org/2004/07/ResponseInfo"
   xmlns:i="http://www.w3.org/2001/XMLSchema-instance" >

You want just:

<ResponseInfo>

Sadly, I haven't seen an easy way yet to remove those fields. I was googling for solutions and most of the options for removing it require creating your own Message inspector, or your own encoder.

christophercotton
+3  A: 

You can remove the XML namespace by setting the Namespace parameter of the DataContract attribute to an empty string, like so:

[DataContract(Namespace = "")]
public class ResponseInfo
{
    // ...
}

I hope this helps...

Kevin Babcock
This works but you may need to put [DataMember] attributes on fields to ensure that the xml is not empty
Simon Munro
From my tests, this method does not get rid of the xmlns:i="http://www.w3.org/2001/XMLSchema-instance" declaration
Darrel Miller
+3  A: 

If you want to change Xml, one of the ways is to use an XslTransform. I had a similar case, where I needed to remove the xmlns attributes from an Xml Post request.

In WCF you can 'intercept' the Xml messages before the go out, or before they are processed on the way in, by implementing either the IClientMessageInspector or the IDispatchMessageInspector, depending on whether you need this at the client or the server side.

For instance, to strip the namespace attributes from an outgoing Xml message to a web service, I implemented the IClientMessageInspector, using the following code:

#region IClientMessageInspector Members
    public void AfterReceiveReply(ref Message reply, object correlationState)
    {   
        //Console.WriteLine(reply.ToString());
    }

    private XslCompiledTransform xt = null;

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        Console.WriteLine(request.ToString());
        if (!request.IsEmpty)
        {
            XmlReader bodyReader =
                request.GetReaderAtBodyContents().ReadSubtree();

            MemoryStream ms = new MemoryStream();
            XmlWriter xw = XmlWriter.Create(ms);

            if (xt == null)
            {
                xt = new XslCompiledTransform(true);
                xt.Load("StripXmlnsi.xslt");
            }
            xt.Transform(bodyReader, xw);

            ms.Flush();
            ms.Seek(0, SeekOrigin.Begin);

            bodyReader = XmlReader.Create(ms);

            Message changedMessage = Message.CreateMessage(request.Version, null, bodyReader);
            changedMessage.Headers.CopyHeadersFrom(request.Headers);
            changedMessage.Properties.CopyProperties(request.Properties);
            request = changedMessage;
        }
        return null;
    }
    #endregion

and used the following transform:

    <?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  <xsl:template match="*">
    <!-- remove element prefix (if any) -->
    <xsl:element name="{local-name()}">
      <!-- process attributes -->
      <xsl:for-each select="@*">
        <!-- remove attribute prefix (if any) -->
        <xsl:attribute name="{local-name()}">
          <xsl:value-of select="." />
        </xsl:attribute>
      </xsl:for-each>
      <xsl:apply-templates />
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Hope this is helpfull.

Bernie
+1  A: 

Just to give the other perspective, if the namespace is unique to your project, e.g:

http://mycompany.com/myapi/

then it should be retained.

Such namespaces are best practice, they'll add less than 1 line of boilerplate to any XPath calls (which you can turn into a helper method) and require about 15 lines of helper code to generate a prefix/URI map, but that is the ONLY downside and you won't always encounter it.

In exchange you get unambiguous names for every element and that means you can compose third party namespaces with impunity e.g. in theory you could return XHTML directly without application level encoding.

Other namespaces turning up is unlikely to be an issue, as they are unlikely to be used on any of the tags that you defined in your project. In fact, if they are, then there is a bug somewhere. The likely explanaintion for there existence is that the framework added them just in case it needed to add an element somewhere below the spot where they are declared, which may not be a location you have to care about.

Another answer mentioned http://www.w3.org/2001/XMLSchema-instance which is a bit special, perhaps you could say what namespaces were added.

Simon Gibbs