Creating RESTful WCF Web Services Using Visual Studio 2010

Representational State Transfer (REST) is an architectural style used to build distributed systems. First proposed in 2000 by Roy Thomas Fielding in his doctoral dissertation “Architectural Styles and the Design of Network-based Software Architectures”, REST is now, or will soon be, the predominant architecture for building web services. However, there’s a lot of discussion about the true definition of a RESTful web service. One real world discussion that helped me understand RESTfulness is this article from IBM’s Alex Rodriguez. My own, rather distilled, working definition of a RESTful service is one that uses the standard HTTP verbs POST, GET, PUT and DELETE – as intended and defined in RFC 2616 – and a URI to accomplish resource CRUD (create, read, update, delete).1

As a .NET developer, I use Windows Communication Foundation (WCF) to create web services. This post shows you how to use Visual Studio 2010 to create a basic REST service that supports each HTTP verb.

Create a WCF Service Application project named RestService:

Delete IService1.cs and Service1.cvs that were created for you by VS:

Add a new WCF service named JazzArtists:

Visual studio will add 2 files to your project named IJazzArtists.cs and JazzArtists.svc and its associated code behind page.

Next, we need to write the service contract. Replace the contents of IJazzArtists.cs with the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;

namespace RestService
{
    [DataContract]
    public class Person
    {
        [DataMember]
        public string FirstName { get; set; }

        [DataMember]
        public string LastName { get; set; }

        [DataMember]
        public int Grammys { get; set; }

        public Person(string firstName, string lastName, int grammys)
        {
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Grammys = grammys;
        }
    }

    [ServiceContract]
    public interface IJazzArtists
    {
        [OperationContract]
        [WebInvoke(Method = "GET",
            ResponseFormat = WebMessageFormat.Xml,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "xml/{id}")]
        string XMLData(string id);

        [OperationContract]
        [WebInvoke(Method = "GET",
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "json/{firstn}")]
        List<Person> JSONData(string firstn);

        [OperationContract]
        [WebInvoke(Method = "GET",
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "json")]
        List<Person> JSONDataAll();

        [OperationContract]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "json")]
        bool JSONDataPost(Person PersonObject);

        [OperationContract]
        [WebInvoke(Method = "DELETE",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "json")]
        bool JSONDataDelete(Person PersonObject);

        [OperationContract]
        [WebInvoke(Method = "PUT",
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "json")]
        bool JSONDataPut(Person PersonObject);


    }
}

The [DataContract] defines the data types and structures of resources that will be transferred between your application and the web service. The [ServiceContract] defines how each HTTP verb request to the specifed URI will be handled by the web service.

In this example, the first [OperationContract] is for GET requests made to URLs constructed like http://yourdomain.com/RestService.svc/xml/Shirley. All requests to this URL will receive an XML response since ResponseFormat = WebMessageFormat.Xml on code line 36. The XML returned data

  <XMLDataResponse xmlns="http://tempuri.org/">
  <XMLDataResult>Your name is Shirley</XMLDataResult> 
  </XMLDataResponse>

is the result of the method XMLData(string id) – which we’ll discuss momentarily.

The next [OperationContract] is for a GET request to URLs like http://yourdomain.com/RestService.svc/json/Shirley. The result returned from this request is a in JSON formatted Person list with one row, for example:

{"JSONDataResult":[{"FirstName":"Shirley","Grammys":1,"LastName":"Horn"}]}

The next GET contract is used to read all Persons. Notice it has a different URI than the previous. In the first URI – /json/{firstn} – we specified which person to get. The second URI does not. So when you GET from http://yourdomain.com/RestService.svc/json, the return is a list of all Persons:

{"JSONDataAllResult":[{"FirstName":"Billie","Grammys":10,"LastName":"Holiday"},
                      {"FirstName":"Shirley","Grammys":4,"LastName":"Horn"},
                      {"FirstName":"Ella","Grammys":20,"LastName":"Fitzgerald"}]}

The POST [OperationContract] for the URL http://yourdomain.com/RestService.svc/json expects the posted data in the request package to conform to the Person class definition and to be in JSON format:

{"PersonObject":{"FirstName":"Shirley","LastName":"Horn","Grammys":4}}

Notice the JSON wrapper key name “PersonObject” is the same name used in the POST [OperationContract] on code line 61. We will discuss the requirements for the “input” data of the POST request in greater detail in my next post.

The response to the POST request is the JSON formatted result of method JSONDataPost(Person PersonObject).

{"JSONDataResult":true}

PUT and DELETE are similarly implemented.

Now we need to define the methods that run when the HTTP requests are made to the URIs. Replace the contents of JazzArtists.svc.cs with this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace RestService
{
    public class JazzArtists : IJazzArtists
    {

        public string XMLData(string id)
        {
            return "Your name is " + id;
        }

        public List<Person> JSONData(string firstn)
        {   //code to Read ONE person goes here
            string lastn = "Horn";
            int nogrammys = 1;
            List<Person> players = new List<Person>();
            players.Add(new Person(firstn, lastn, nogrammys));
            return players;
        }

        public List<Person> JSONDataAll()
        {   //code to Read ALL Persons go here
            List<Person> players = new List<Person>();
            players.Add(new Person("FirstName", "LastName", 0));
            return players;
        }

        public bool JSONDataPost(Person PersonObject)
        {   //code to Create the Person goes here
            return true;
        }

        public bool JSONDataDelete(Person PersonObject)
        {   //code to Delete the specified Person
            return true;
        }

        public bool JSONDataPut(Person PersonObject)
        {   //code to Update the specified Person goes here
            return true;
        }
    }
}

How easy is that! Just fill in the details for your project and make sure your method names and types are the same as those specifed in the contract.

Finally, since the default communication binding for a WCF web services is SOAP, we need to change the web.config to use REST instead.

In the system.serviceModel section, delete both the service for Service1:

and the associated behavior:

since we have deleted Service1 from the project. Also delete the indentity in your JazzArtists service:

WCF will infer an appropriate identity automatically.

Now change the endpoint binding for JazzArtists to webHttpBinding and the behaviorConfiguration to web. Add the endpointBehaviors section as well:

The system.serviceModel should look like this:

<system.serviceModel>
    <services>
      <service behaviorConfiguration="RestService.JazzArtistsBehavior"
        name="RestService.JazzArtists">
        <endpoint address="" binding="webHttpBinding" 
          contract="RestService.IJazzArtists" behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="RestService.JazzArtistsBehavior">
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

You may need to make more changes to your web.config depending upon the hosting environment. Mine runs on a shared hosting plan so I had to add a serviceHostingEnvironment section to my system.serviceModel to specify the correct prefix:

I also had to add a buildProviders in the compilation section to properly handle .svc files:

You can test drive a working REST service similar to this one on my development site example WCF RESTful Web Service. My next post will demonstrate how to consume a REST service using client side jQuery and Ajax.


1. This post concentrates on the details of creating a REST service using WCF and Visual Studio 2010. However, the service we built is not as RESTful as it could be. A future post will demonstrate a few changes that will better align this web service with the principles of REST and Resource Oriented Architecture.

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