WCF- Changing Data Contract Names and Namespaces

When posting XML data to a Windows Communication Foundation (WCF) web service1, you need to specify the XML namespace of the data sent in the entity-body of your HTTP POST. This lets WCF know how to deserialize the input you’ve sent. By default, WCF maps the namespace to:

http://schemas.datacontract.org/2004/07/Clr.Namespace

where Clr.Namespace is the namespace of your data contract.2 For example, if my data contract namespace is “RESTful”:

namespace RESTful
{
    [DataContract]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }
        //...

then the namespace to use when consuming this service is:

http://schemas.datacontract.org/2004/07/RESTful

Here’s a code snippet that uses jQuery and Ajax to post a Person to the WCF web service:

        $.ajax({
            type: 'POST',
            data: '<Person xmlns="http://schemas.datacontract.org/2004/07/RESTful">'
                  + '<ArtistID>0</ArtistID>'
                  + '<FirstName>Ella</FirstName>'
                  + '<Grammys>14</Grammys>'
                  + '<LastName>Fitzgerald</LastName>'
                  +'</Person>',
            dataType: 'xml',
            // ...

That’s not a descriptive namespace. Let’s change it to something a bit more informative by specifying a ContractNamespace for our assembly.

[assembly: ContractNamespace("http://schemas.dlwelch.com/JazzService", ClrNamespace = "RESTful")]
namespace RESTful
{
    [DataContract]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }
        //...

Putting this at the assembly level changes the namespace for all data contracts in the RESTful namespace. If we didn’t want to change them all, we could have changed a single contract like this:

namespace RESTful
{
    [DataContract (Namespace="http://schemas.dlwelch.com/JazzService")]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }
        //...

I’m going to leave all of the RESTful data contracts in the same namespace (line 1). And while I’m under the hood, I’m going to change the contract name to something more meaningful (line 4):

[assembly: ContractNamespace("http://schemas.dlwelch.com/JazzService", ClrNamespace = "RESTful")]
namespace RESTful
{
    [DataContract(Name = "Artist")]
    public class Person
    {
        [DataMember]
        public int ArtistID { get; set; }
        //..

Now, when we POST to the service, the request details are a lot nicer:

        $.ajax({
            type: 'POST',
            data: '<Artist xmlns="http://schemas.dlwelch.com/JazzService">'
                  + '<ArtistID>0</ArtistID>'
                  + '<FirstName>Ella</FirstName>'
                  + '<Grammys>14</Grammys>'
                  + '<LastName>Fitzgerald</LastName>'
                  + '</Artist>',
            dataType: 'xml',
            // ...         

My ultimate goal is to create a truly RESTful web service. That’s why I want everything to be self-describing – including the namespace for my data contracts. It also means I’m not interested in the WSDL which is auto-generated by WCF. However, changing the contract names and namespaces has the added bonus of making your WSDL nicer too!

A default WSDL would be similar to this:

<?xml version="1.0" encoding="UTF-8"?>
 <wsdl:definitions name="JazzArtists" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" 
    ... 
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
    xmlns:tns="http://tempuri.org/" 
    ... 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                targetNamespace="http://tempuri.org/">
 <wsdl:types>
  <xsd:schema targetNamespace="http://tempuri.org/Imports">
    <xsd:import namespace="http://tempuri.org/"
         schemaLocation="http://development.dlwelch.com/examples/RestService/JazzArtists.svc?xsd=xsd0"/>
    <xsd:import namespace="http://schemas.microsoft.com/2003/10/Serialization/" 
       schemaLocation="http://development.dlwelch.com/examples/RestService/JazzArtists.svc?xsd=xsd1"/>
    <xsd:import namespace="http://schemas.datacontract.org/2004/07/RestService" 
       schemaLocation="http://development.dlwelch.com/examples/RestService/JazzArtists.svc?xsd=xsd2"/>
   </xsd:schema>
 </wsdl:types>
 <wsdl:message name="IJazzArtists_XMLData_InputMessage">
 <wsdl:part name="parameters" element="tns:XMLData"/>
  ... 
</wsdl:definitions>

There are multiple references to “http://tempuri.org/” in addition to the data contract namespace “http://schemas.datacontract.org/2004/07/RestService”. We’ve already cleaned up the latter (line 15), now let’s get rid of tempuri.org. First, we’ll change the namespace for the service contract:

[ServiceContract ( Namespace = "http://schemas.dlwelch.com/JazzService" )]
public interface IJazzService
{

and then the service implementation:

namespace RESTful
{
    [ServiceBehavior(Namespace = "http://schemas.dlwelch.com/JazzService")]
    public class JazzService : IJazzService
    { 
      //...

Finally, we’ll change the namespace for the binding in the web.config:

  <system.serviceModel>
    <services>
      <service behaviorConfiguration="RESTful.JazzServiceBehavior" name="RESTful.JazzService">
        <endpoint address="" binding="webHttpBinding" 
                             bindingNamespace="http://schemas.dlwelch.com/JazzService" 
                             contract="RESTful.IJazzService" behaviorConfiguration="web">
        </endpoint>
   ...

This gives us WSDL using our custom namespaces instead of the WCF defaults:

<?xml version="1.0" encoding="UTF-8"?>
 <wsdl:definitions name="JazzService" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" 
    ... 
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
    xmlns:tns="http://schemas.dlwelch.com/JazzService" 
    ...
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                targetNamespace="http://schemas.dlwelch.com/JazzService">
  <wsdl:types>
  <xsd:schema targetNamespace="http://schemas.dlwelch.com/JazzService/Imports">
    <xsd:import namespace="http://schemas.dlwelch.com/JazzService" 
         schemaLocation="http://development.dlwelch.com/examples/restful/JazzService.svc?xsd=xsd0"/>
    <xsd:import namespace="http://schemas.microsoft.com/2003/10/Serialization/" 
         schemaLocation="http://development.dlwelch.com/examples/restful/JazzService.svc?xsd=xsd1"/>
  </xsd:schema>
  </wsdl:types>
 <wsdl:message name="IJazzService_GetArtist_InputMessage">
 <wsdl:part name="parameters" element="tns:GetArtist"/>
...
</wsdl:definitions>

I haven’t “switched off” the WSDL for my JazzService even though the service will eventually be RESTful. There’s no harm to ROA by leaving it on. So if someone wants to create a client by importing the WSDL, it’s now available with our nice namespaces.


1. Please see my blog post Creating RESTful WCF Web Services Using Visual Studio 2010 for an example of creating WCF web services.
2. Data Contract Names – http://msdn.microsoft.com/en-us/library/ms731045.aspx

Tagged with: , , ,
Posted in WCF, Web Services
Advertisement