Monday, August 10, 2009

Creating RESTful web services in .NET

This blog is about creating RESTful web services using Windows Communicaiton Foundation (WCF) in .NET. The intention of this blog is not to teach what is Representation State Transfer (REST) but how to create web services which support REST by making use of WCF. So lets start by having a look at what was the requirement which prompted me to create a RESTful web service and how we did it.

As with any change in software, this change, to have RESTful web service was also raised by the client. The client in our case had some Business Access Layer (BAL) and he wanted to expose some of the methods to the outside world through RESTful web service. So what we did was we created a Facade layer to expose the required methods of the BAL and called exposed this Facade layer with the help of WCF web service. Thats the simple solution to our requirement. Now lets see the code wise implementation of the solution.

As per company rules and other client agreement I may not be able to publish the same implementation but will try to take another e.g. and try to replicate the same scenario and create RESTful web services. We will see two ways of creating WCF, one is implementing the interface in class file and then exposing the class methods using a .SVC file and second approach is the default way i.e. implementing an interface to a .SVC file. Lets see the first way (this was the solution implemented to solve our problem).

For creating a WCF service first thing you need is a contract. A contract is nothing but an Interface with the methods you want to expose. So lets create our contract (interface) which will be implemented by the WCF service. Any WCF webservice (RESTful or non RESTful) needs a contract, if no contract is defined then the class should be have the ServiceContract attribute to it and this is mandatory. Below is the interface definition.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CarService
{
    [System.ServiceModel.ServiceContract]
    public interface ICarService
    {
       [System.ServiceModel.OperationContract] 
       [System.ServiceModel.Web.WebGet(UriTemplate="cars", 
         ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Xml)]
        List<Car> GetCars();

       [System.ServiceModel.OperationContract] 
       [System.ServiceModel.Web.WebGet(UriTemplate="cars/search?carName={theCarName}")]
        Car GetCar(string theCarName);
    }
}

From the above interface definition one can see that we are using some attributes. Lets see each of these attributes one by one. First up is the ServiceContract attribute.

ServiceContract: This attribute tells the system that the interface defines a service contract for a WCF application. If an interface which is being inherited by a WCF web service doesn’t have a ServiceContract attribute then the following error will thrown by the system.

Service 'CarService' implements multiple ServiceContract types, and no endpoints are defined in the configuration file. WebServiceHost can set up default endpoints, but only if the service implements only a single ServiceContract. Either change the service to only implement a single ServiceContract, or else define endpoints for the service explicitly in the configuration file.

Just applying the ServiceContract attribute above the interface will solve the above error. Now lets see the various properties associated with the ServiceContract attribute

Property Description
ConfigurationName

The element name in the configuration file which defines the service.

Name

Using the property you can provide a different name to the interface.

Namespace Can be used to provide namespace.
ProtectionLevel

enum value specifies what type of protection should be applied to the service. The enum values are ProtectionLevel.None, ProtectionLevel.Sign and ProtectionLevel.EncryptAndSign

SessionMode

enum specifies whether sessions are allowed or not. The enum values are SessionMode.Allowed, SessionMode.Required and SessionMode.NotAllowed.

That’ about ServiceContract attribute. The next attribute which we have used in all the methods is the OperationContract attribute. Lets see what does OperationContract do.

OperationContract: OperationContract attribute tells the system that the method needs to be exposed as part of a service contract. A method which is not having OperationContract will not be exposed. So its imperative to have OperationContract attribute to expose a method. The properties which can be used along with OperationContract are.

Property Description
Action

Using the action property you can specify a url to which the incoming messages needs to be posted. Action uniquely identifies a method with a Url.

AsyncPattern

Specifies whether the method can be called asynchronously or not.

IsOneWay

Specifies whether the operation returns a value or not.

IsInitiating

Specifies whether the method needs to be called when session is started.

IsTerminating

Tells the system to execute the method when session is completed.

Name

If you want to give some other name to the method then you can make use of the name property.

ProtectionLevel

enum value specifies what type of protection should be applied to the service. The enum values are ProtectionLevel.None, ProtectionLevel.Sign and ProtectionLevel.EncryptAndSign

Next attribute which you will notice is the WebGet. Here is the explanation of WebGet attribute.

WebGet: If you would have worked on ASP.NET application then you know that the forms in ASP.NET post data in two ways, one is the GET method and the other one is the POST method. WebGet attribute tells the system that the method is a pure data retrieval method to which HTTP GET method is associated. The properties associated with WebGet are listed below.

Property Description
BodyStyle

enum specifies how messages should be sent. Enum values are WebMessageBodyStyle.Bare, WebMessageBodyStyle.Wrapped, WebMessageBodyStyle.WrappedRequest and WebMessageBodyStyle.WrappedResponse.

RequestFormat

enum specifies what is the request format. Enum values are WebMessageFormat.Xml and WebMessageFormat.Json.

ResponseFormat

Same as RequestFormat. Specifies the type of the response.

UriTemplate

The Uri to access the method/operation.

UriTemplate here is the endpoint. Here endpoint means a unique Url to access the method in a restful webservice. This is one of the requirement of a RESTful method which says there should be unique endpoint to access the methods.

One thing to note in UriTemplate property is that whatever you specify inside a curly brace, {}, and if the same name is used in the parameter of the method then the value which comes in the querystring is passed on as the parameter for the method. In our second method in the interface we have given the UriTemplate as something like this “cars/search?carName={theCarName} ” which means the querystring value in carName will be passed as the parameter to the method, as the parameter name and value inside the curly brace are the same. If you want more parameters you can very well do this by declaring more parameters in the querystring. A hypothetical method is pasted below.

[System.ServiceModel.OperationContract]
[System.ServiceModel.Web.WebGet(UriTemplate = "cars/Carsearch?carName={theCarName}&color={theColor}&price={thePrice}")]
Car SearchCar(string theCarName, string theColor, string thePrice);

In the above e.g. theCarName, theColor and thePrice will be passed as parameter to the method SearchCar. The url may look something like this “http://localhost:2333/cars/carsearch?carName=ferrari&color=red&price=432544”. The values ferrari, red and 432544 will be passed as parameters to the SearchCar method. So if you want to pass parameters to a RESTful web method then you need to just follow the above approach.

Now that was about making use of HTTP GET method. The next obvious question would be how to make use of HTTP POST method. To make use of HTTP POST method one need to apply another attribute called “WebInvoke” All the properties are same as in WebGet except for an extra property called Method. Using the method property you can specify the HTTP method like POST, PUT, DELETE and HEAD. When to use each of these HTTP method is given below.

HTTP Method Description
GET Whenever you want to retrieve some information you will make use of get.
POST When you want to submit data which will be processed by the service.
PUT When you want create or update a resource you will make use of PUT.
DELETE As the name suggest whenever you want to delete a resource you will make use of DELETE.

Now we have our contract defined. So the first step is over. Now we need to implement the interface and that is what we are going to do next. We will be implementing the interface in a class called CarService. The code is pasted below.

namespace CarService
{
    public class CarService : ICarService
    {
        List<Car> carList;
        public CarService()
        {
            carList = new List<Car> {new Car{ModelName="Ferrari", Color="Ferrari Red", CubicCentimeter= "2345",
             Price=34324324}, new Car{ModelName="BMW 3 Series", Color="Blue", CubicCentimeter= "2200",
             Price = 32423}, new Car{ModelName="Benz SLR", Color="Milky White", CubicCentimeter = "3200",
             Price = 32424}};//Storing the car objects in a collection
        }
        List<Car> ICarService.GetCars()
        {
            return carList;
        }

        Car ICarService.GetCar(string theCarName)
        {          
            var car = from c in carList where c.ModelName == theCarName select c;
            Car cs = null;
            foreach (var c in car)
            {
                cs = c as Car;
            }
            return cs;
        }
    }
}

You can see from the above code we have implemented ICarService interface into a class called CarService. The first method returns the Car collection and the second method searches the carList collection object based on the name of the car and returns the matching Car object. No rocket science here. The Car class is discussed in detail at the end of the blog. So we will move on to the next step.

We have defined the base requirement and now we have to expose the methods to the outside world using WCF service. For that you can either add a new WCF Service Applicaiton project from the file menu or you can right click on your ASP.NET or web service project and from the popup menu select Add—>New Item option. From the Add New Item dialog box select WCF Service and give a name to your service. I have named it CarService. The screenshot of Add New Item dialog is pasted below.

image

You can do the same from file menu as well.

When you add WCF Web service application or a SVC file the system will automatically add an interface by the name ICarService or I followed by whatever name given to the project or SVC file. Delete the interface, as we have already defined the contract. Also delete the SVC.cs file. Now open the SVC file, in my case CarService.svc. You can see a markup something like this.

<%@ ServiceHost Language="C#" Debug="true" Service="CarService.CarService" CodeBehind="Service1.svc.cs" %>

Delete the CodeBehind attribute and add Factory attribute as shown below.

<%@ ServiceHost Language="C#" Debug="true"
Service="CarService.CarService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>

You may get an error something like the one pasted below.

Service 'CarService.CarService' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.

If you come across an error like this then the possible reason could be you will be missing the Factory attribute in the ServiceHost tag. Just by adding the Factory attribute will solve the prob.

Visual studio also embeds the following tag in Web.config file.

<system.serviceModel>
        <behaviors>
   <serviceBehaviors>
    <behavior name="RestFulWebservice.CarServiceBehavior">
     <serviceMetadata httpGetEnabled="true" />
     <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>   
   </serviceBehaviors>
  </behaviors>
        <services>
   <service behaviorConfiguration="RestFulWebservice.CarServiceBehavior"
    name="RestFulWebservice.CarService">
    <endpoint address="" binding="wsHttpBinding" contract="CarService.ICarService">
     <identity>
      <dns value="localhost" />
     </identity>
    </endpoint>
    <endpoint address="" binding="mexHttpBinding" contract="IMetadataExchange" />   
   </service>
  </services>
</system.serviceModel>

Now you are ready to go. Just hit F5 and see the output. If you see a message saying there is no endpoint defined you need not panic. Just type one of the endpoints defined in the contract (interface) you can see the output. In my case the two url which I used are as follows.

http://localhost:3891/CarService.svc/cars
Ouput of the above url

<GetCarsResponse xmlns="http://tempuri.org/">
     <GetCarsResult xmlns:a="http://schemas.datacontract.org/2004/07/CarService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
         <a:Car>
          <a:Color>Ferrari Red</a:Color>
          <a:CubicCentimeter>2345</a:CubicCentimeter>
          <a:ModelName>Ferrari</a:ModelName>
          <a:Price>34324324</a:Price>
          </a:Car>
         <a:Car>
          <a:Color>Blue</a:Color>
          <a:CubicCentimeter>2200</a:CubicCentimeter>
          <a:ModelName>BMW 3 Series</a:ModelName>
          <a:Price>32423</a:Price>
          </a:Car>
         <a:Car>
          <a:Color>Milky White</a:Color>
          <a:CubicCentimeter>3200</a:CubicCentimeter>
          <a:ModelName>Benz SLR</a:ModelName>
          <a:Price>32424</a:Price>
          </a:Car>
      </GetCarsResult>
</GetCarsResponse>

http://localhost:3891/CarService.svc/cars/search?carName=Ferrari

Output of the above url.

<Car xmlns="http://schemas.datacontract.org/2004/07/CarService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Color>Ferrari Red</Color>
  <CubicCentimeter>2345</CubicCentimeter>
  <ModelName>Ferrari</ModelName>
  <Price>34324324</Price>
</Car>

The car class which is getting serialized is shown below.

[System.Runtime.Serialization.DataContract]
public class Car
{       
        [System.Runtime.Serialization.DataMember]
        public string Color
        { get; set; }
        [System.Runtime.Serialization.DataMember]
        public string ModelName
        { get; set; }
        [System.Runtime.Serialization.DataMember]       
        public int Price
        { get; set; }
        [System.Runtime.Serialization.DataMember]
        public string CubicCentimeter
        { get; set; }
}

The objects used in WCF should be qualified by DataContract attribute. Some of the properties of DataContract are listed below.

Property Description
Name If you want to give a different name to the class when it is serialized then you can make use of the name property.
Namespace To provide a namespace to the xml attribute you can make use of the “Namespace” property. When you provide namespace it has abide by w3 guidelines. As a general practice we provide urls as namespace.

The other attribute is the DataMember. DataMember attribute tells the serializer that the property/field is part of a DataContract and it can be serilizable. Some of the properties are explained below.

Property Description
EmitDefaultValue Property which tells the serializer whether to emit default value if the property is not having any value.
IsRequired This property can be set when you want the property/field to be present while serializing and deserializing the object.
Name If you want to give some other name other than name of the property/field then you can make use the Name property.
Order When the object is serialized in what order the property/field needs to be serialized.

Now lets see the second way of implementing the WCF webservice. This is the most common way which everyone will be aware off. Open VS 2008 and add a new project of type WCF Service Application from File—>New—>Project menu. This will automatically add a contract (interface) and the necessary .SVC files (a .svc and a .svc.cs file inheriting from the interface). Rest we need to follow the same steps for defining various methods in the Interface as explained above.

8 comments:

  1. Its really a helpful post for me as I am creating a web application in .Net at Imenso Sotware which provides web development in .NET ,Software development .NET and other Offshore It Services.

    ReplyDelete
  2. Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your

    blog posts.

    saab service contract

    ReplyDelete
  3. Great thanks! Very helpful for me.

    ReplyDelete
  4. Very well written and explained ! Thanks.

    ReplyDelete

Please provide your valuable comments.