WCF – Including XML Attributes in Your DataContract

RESTful web services must include hypertext within their resource representations to fulfill the HATEOAS constraint.1 XML attributes within a <link> element have become a standard part of this hypertext. The Atom Publishing Protocol is considered to be quite RESTful2 and defines several attributes for a <link>. This Atom <links> has “rel” and “href” attributes that indicate where to PUT data to edit the resource:

<link rel=”edit” href=”http://example.org/blog/entries/1″ />

Unfortunately, WCF’s default “…DataContractSerializer does not support the programming model used by the XmlSerializer and ASP.NET Web services. In particular, it does not support attributes like XmlElementAttribute and XmlAttributeAttribute. To enable support for this programming model, WCF must be switched to use the XmlSerializer instead of the DataContractSerializer.”3 This post shows you how to switch to the XmlSerializer.

First, use Visual Studio 2010 to create a new WCF Service application. Next, open the IService1.cs file and replace the auto-generated code with this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web; //add reference if needed
using System.Text;
using System.Xml.Serialization; //add reference if needed

namespace YourNameSpaceHere
{

   [ServiceContract]
   [XmlSerializerFormat]
   public interface IService1
   {
      [OperationContract]
      [WebInvoke(Method = "GET",
          ResponseFormat = WebMessageFormat.Xml,
          UriTemplate = "artist")]
      Artist GetArtist();
   }

   [DataContract]
   [XmlRoot(ElementName = "Artist")]
   public class Artist
   {
      [XmlAttribute("rel")]
      public string theUri { get; set; }

      public string FirstName { get; set; }
      public string LastName { get; set; }
      public string Grammys { get; set; }

      public Artist() { }

      public Artist(string firstName, string lastName, string grammys)
      {
         this.theUri = "edit";
         this.FirstName = firstName;
         this.LastName = lastName;
         this.Grammys = grammys;
      }
   }
}

The code above tells WCF to use the XmlSerializerFormat for your service contract. Then we decorate the DataContract with the attributes required to tell WCF which property is the XML root, an XML attribute and an XML element. When using the XmlSerializer, unlike the DataContractSerializer, if an attribute is not defined for a public data member (like the FirstName property) WCF serializes the member as an XML element. This is important to remember! Otherwise you could accidentally expose a property that had not been exposed using the default WCF DataContract serialization.

Now open Service1.svc.cs and replace the existing code with the following. There’s nothing new in this file related to the XmlSerializer. I’m just including it so you’ll have a working service to test.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;        //add reference if needed
using System.Text;
using System.ServiceModel.Activation; //add reference if needed

namespace YourNameSpaceHere
{
   public class Service1 : IService1
   {
      public Artist GetArtist()
      {
         Artist player = new Artist("LastName", "FirstName", "0");
         return player;
      }
   }
}

Finally, right click the Services1.svc file and View Markup:

Add the Factory=”System.ServiceModel.Activation.WebServiceHostFactory” attribute as follows. This tells WCF to dynamically generate the host instance in IIS, and therefore the endpoints configurations, so we can avoid doing it in the Web.config. It’s not related to using the XmlSerializer:

<%@ ServiceHost Language="C#" Debug="true" 
Service="YourNameSpaceHere.Service1" CodeBehind="Service1.svc.cs" 
Factory="System.ServiceModel.Activation.WebServiceHostFactory"%>

Build and test your service. You can test your service by right clicking the Service1.svc file and then “View in Browser”. This will take you to http://localhost:55802/Service1.svc which is not defined as an endpoint. Now browse to http://localhost:55802/Service1.svc/artist. You’ll get this following XML with the attribute rel=”edit” in the Artist element on line 2.

<?xml version="1.0" encoding="utf-8" ?> 
<Artist rel="edit" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <FirstName>LastName</FirstName> 
  <LastName>FirstName</LastName> 
  <Grammys>0</Grammys> 
</Artist>

1. Fielding, Roy T. REST APIs must be hypertext-driven. Untangled – Musings of Roy T. Fielding, October 20, 2008

2. Richardson, Leonard and Ruby, Sam. RESTful Web Services. Sebastopol: O’Reilly Media, Inc., 2008. Ebook

3. MSDN. Types Supported by the Data Contract Serializer 2012-08-02

Tagged with: , ,
Posted in WCF
Advertisement