Simple WCF. RESTful and SOAP endpoint at one contract.

By Mirek on (tags: REST, SOAP, WCF, web service, categories: code)

REST (Representational state transfer) web service is a service over HTTP with specific architecture. The REST is then an architectural style, which defines the rules of accessing resources exposed in the web. In principle the restful service exposes some sort of resource, for instance collection of entities, which can be easily accessed and changed from external client. To be consistent with REST principles, the service must expose certain set of HTTP method which are for instance

  • GET – to get the resource or resources
  • POST – to submit new resource
  • PUT – to replace existing resource
  • DELETE – to remove resource

I recommend to take a look at Ryan Tomayko's How I Explained REST to My Wife which in simple way explains the point of using RESTful services.

Let’s see how we can easily expose service in two different endpoints, one standard SOAP web service and one as RESTful service.

Let’s say we have an collection of following simple objects

   1: public class SampleItem
   2: {
   3:     public int Id { get; set; }
   4:     public string StringValue { get; set; }
   5: }

We want to add a possibility to get all items, get item by id, add new item, update item and delete item. The contract would look as follows

   1: [ServiceContract(Namespace="")]
   2:   [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
   3:   public class SampleService
   4:   {
   5:       private static Dictionary<string, SampleItem> repo = new Dictionary<string, SampleItem>
   6:       {
   7:          {"1", new SampleItem{Id = 1, StringValue = "First sample"}},
   8:          {"2", new SampleItem{Id = 2, StringValue = "Second sample"}},
   9:          {"3", new SampleItem{Id = 3, StringValue = "Third sample"}}
  10:       };
  11:  
  12:       [WebGet(UriTemplate = "")]
  13:       public List<SampleItem> GetCollection()
  14:       {
  15:           return repo.Values.ToList();
  16:       }
  17:  
  18:       [WebInvoke(UriTemplate = "", Method = "POST")]
  19:       public SampleItem Create(SampleItem instance)
  20:       {
  21:           repo.Add(instance.Id.ToString(), instance);
  22:           return instance;
  23:       }
  24:  
  25:       [WebGet(UriTemplate = "{id}")]
  26:       public SampleItem Get(string id)
  27:       {
  28:           return repo[id];
  29:       }
  30:  
  31:       [WebInvoke(UriTemplate = "{id}", Method = "PUT")]
  32:       public SampleItem Update(string id, SampleItem instance)
  33:       {
  34:           if (repo[id] != null)
  35:               repo[id] = instance;
  36:           else
  37:               repo.Add(instance.Id.ToString(), instance);
  38:           return instance;
  39:       }
  40:  
  41:       [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
  42:       public void Delete(string id)
  43:       {
  44:           if (repo[id] != null)
  45:               repo.Remove(id);
  46:       }
  47:   }

Private static repo acts here as a kind of repository, just for the simplicity.

The configuration for the service looks like this

   1: <system.serviceModel>
   2:   <services>
   3:     <service name="RestServ.SampleService" >
   4:       <endpoint address="" contract="RestServ.SampleService" binding="basicHttpBinding" />
   5:       <endpoint address="/rest" contract="RestServ.SampleService" binding="webHttpBinding"
   6:                 behaviorConfiguration="web"/>
   7:     </service>
   8:   </services>
   9:   <behaviors>
  10:     <serviceBehaviors>
  11:       <behavior >
  12:         <serviceMetadata httpGetEnabled="true"/>
  13:       </behavior>
  14:     </serviceBehaviors>
  15:     <endpointBehaviors>
  16:       <behavior name="web">
  17:         <webHttp/>
  18:       </behavior>
  19:     </endpointBehaviors>
  20:   </behaviors>
  21:   <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
  22:     <serviceActivations>
  23:       <add service="RestServ.SampleService" relativeAddress="Service.svc"/>
  24:     </serviceActivations>
  25:   </serviceHostingEnvironment>   
  26: </system.serviceModel>

In lines 4 and 5 we define two endpoints, first as basic Http soap service and second, available under /rest url, REST service. Line 23 is used to avoid having explicit Service.svc file, we define an service activation here instead.

Now assuming the service is running on http://localhost/Service.svc we can access it via HTTP methods:

Method URL request Action
GET http://localhost/Service.svc/rest Returns all items
GET http://localhost/Service.svc/rest/3 Return item with id=3
POST http://localhost/Service.svc/rest Create new item
PUT http://localhost/Service.svc/rest/4 Replace item with id=4
DELETE http://localhost/Service.svc/rest/5 Delete item with id=5