Click here to Skip to main content
Click here to Skip to main content

REST enabled WCF service

, 27 Aug 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Simple WCF RESTful Service, WebGetAttribute and WebInvokeAttribute, UriTemplate and UriTemplateTable. GET, POST, PUT, DELETE.

Table Of Contents


WCF RESTful Service

Introduction

The WCF WEB HTTP Programming Model allows developers to expose Windows Communication Foundation (WCF) Web services through basic HTTP requests without requiring SOAP. The WCF WEB HTTP Programming Model is built on top of the existing WCF extensibility model. Using this article I'm going to explain how to create a REST enabled WCF Service. I have used a simple Patient Sevice to demonstrate the RESFful WCF Service.

What is REST

REST stands for REpresentational State Transfer. The term representational state transfer was introduced and defined in 2000 by Roy Fielding as a concept in his PhD dissertation . The REST is resource based, a resource can be a person, address, user etc and in a RESTful service we will be doing some operations on the resources. The constraints of REST are based on the same underlying principles that govern the Web. Those principles are,

  • User agents interact with resources, and resources are anything that can be named and represented. Each resource can be addressed via a unique Uniform Resource Identifier (URI).
  • Interaction with resources (located through their unique URIs) is accomplished using a uniform interface of the HTTP standard verbs (GET, POST, PUT, and DELETE). Also important in the interaction is the declaration of the resource's media type, which is designated using the HTTP Content-Type header. (XHTML, XML, JPG, PNG, and JSON are some well-known media types.)
  • Resources are self-descriptive. All the information necessary to process a request on a resource is contained inside the request itself (which allows services to be stateless).
  • Resources contain links to other resources (hyper-media).

Wikipedia says about REST as,

Quote:

Representational state transfer (REST) is an abstraction of the architecture of the World Wide Web. More precisely, REST is an architectural style consisting of a coordinated set of architectural constraints applied to components, connectors, and data elements, within a distributed hypermedia system. REST ignores the details of component implementation and protocol syntax in order to focus on the roles of components, the constraints upon their interaction with other components, and their interpretation of significant data elements.

Note: If a REST Service is not having all the specification of REST then the service will be considered as a non-REST service or a service that just looks like REST.

HTTP verbs

HTTP defines methods (sometimes referred to as verbs) to indicate the desired action to be performed on the identified resource. What this resource represents, whether pre-existing data or data that is generated dynamically, depends on the implementation of the server.  I have listed down some of the major HTTP verbs.

Method Description
GET Requests a specific representation of a resource. Requests using GET should only retrieve data and should have no other effect. 
PUT Update the resource if the URI refers to an already existing resource else create it.
DELETE Deletes the specified resource.
POST Submits data to be processed by the identified resource.
HEAD Similar to GET but only retrieves headers and not the body. This is useful for retrieving meta-information written in response headers, without having to transport the entire content.
OPTIONS Returns the HTTP methods that the server supports for the specified URL. This can be used to check the functionality of a web server by requesting '*' instead of a specific resource.

Read more form wikipedia.

WCF and REST

WCF is the Microsoft framework for building applications that communicates over a network, regardless of the style or protocol. The WCF Services has the ability to expose REST services using System.ServiceModel.Web assembly. This ServiceModel gives you two attributes, WebGetAttribute and WebInvokeAttribute and a URI template mechanism that enables you to declare the URI and verb to which each method is going to respond.

The WCF WEB HTTP Programming Model defines the following classes:

Programming Model:

Channels and Dispatcher Infrastructure:

Utility Classes and Extensibility Points:

Read more from msdn

WebGetAttribute and WebInvokeAttribute

The WebGetAttribute attribute indicate that a service operation is logically a retrieval operation and that it can be called by the WCF REST programming model. The association with HTTP Get verb means that the operation is used to retrieve information from the service.

Sample:

[ServiceContract]
public interface ICalculator
{
    [OperationContract]
    [WebGet]
    long Add(long x, long y);

    [OperationContract]
    [WebGet(UriTemplate = "Sub?x={x}&y={y}")]
    long Subtract(long x, long y);

    [OperationContract]
    [WebGet(UriTemplate = "Mult?x={x}&y={y}", BodyStyle = WebMessageBodyStyle.Bare)]
    long Multiply(long x, long y);

    [OperationContract]
    [WebGet(UriTemplate = "Div?x={x}&y={y}", RequestFormat = WebMessageFormat.Xml)]
    long Divide(long x, long y);

    [OperationContract]
    [WebGet(ResponseFormat= WebMessageFormat.Json)]
    long Mod(long x, long y);
}

The WebGetAttribute attribute is applied to a service operation in addition to the OperationContractAttribute and associates the operation with a UriTemplate as well as the HTTP protocol Get verb. Service operations with the WebGetAttribute attribute applied should be logical retrieval operations.

Read more about from WebGetAttribute MSDN.

The WebInvokeAttribute attribute indicating that a service operation is logically an invoke operation and that it can be called by the WCF REST programming model.

Sample:

[ServiceContract]
public interface ICalculator2
{
    [OperationContract]
    [WebInvoke]
    long Add(long x, long y);

    [OperationContract]
    [WebInvoke(UriTemplate = "Sub?x={x}&y={y}")]
    long Subtract(long x, long y);

    [OperationContract]
    [WebInvoke(UriTemplate = "Mult?x={x}&y={y}", BodyStyle = WebMessageBodyStyle.Bare)]
    long Multiply(long x, long y);

    [OperationContract]
    [WebInvoke(UriTemplate = "Div?x={x}&y={y}", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml, ResponseFormat=WebMessageFormat.Xml)]
    long Divide(long x, long y);

    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "Mod?x={x}&y={y}")]
    long Mod(long x, long y);
}

The WebInvokeAttribute attribute is applied to a service operation in addition to the OperationContractAttribute and associates the operation with a UriTemplate as well as an underlying transport verb that represents an invocation (for example, HTTP POST, PUT, or DELETE). The Method property allows you to specify a different HTTP method. By default, all methods that have applied the WebInvokeAttribute respond to POST requests.

Read more about from WebInvokeAttribute MSDN.

UriTemplate and UriTemplateTable

UriTemplate allows you to define a set of structurally similar URIs. Templates are composed of two parts, a path and a query. A path consists of a series of segments delimited by a slash (/). Each segment can have a literal value, a variable value (written within curly braces [{ }], constrained to match the contents of exactly one segment), or a wildcard (written as an asterisk [*], which matches "the rest of the path"), which must appear at the end of the path. The query expression can be omitted entirely. If present, it specifies an unordered series of name/value pairs. Elements of the query expression can be either literal pairs (?x=2) or variable pairs (?x={val}). Unpaired values are not permitted.  Read more about UriTemplate form MSDN.

The following examples show valid template strings:

  • "weather/WA/Seattle"
  • "weather/{state}/{city}"
  • "weather/*"
  • "weather/{state}/{city}?forecast=today
  • "weather/{state}/{city}?forecast={day}

UriTemplateTable is an associative set of UriTemplate objects bound to an object of the developer's choosing. It allows you to match candidate Uniform Resource Identifiers (URIs) against the templates in the set and retrieve the data associated with the matching templates.  Read more about UriTemplateTable form MSDN.

Sample Patient REST Service

Project

Creating a WCF Service Application named "PatientService"

WCF Application

Rename IService1 and its reference to IPatientService

Rename Service1 and its reference to PatientService

Database and Table

AddNew Item

Add New Item Visual Studio Project

Select SQL Server Database template and name it as PatientInformation.mdf

Add New SQL Server Database to Visual Studio Project

Open Server Explorer

Server Explorer Visual Studio

Create a table named "Patient" using New Query

SQL New Query Visual Studio

SQL Database Table Creation Visual Studio

Entity Model

Add PatientModel.edmx using Add New Item.

Entity Framework Model

As we have already created the database, select the option "Generate from database"

EF Database First Approach

Select the database

Choose Database

Choose your version

Choose your Entity Framework Version

Select the Table object

EF Table Object

Project Structure

WCF REST Service Project Structure

IPatientService

REST Service Contract

Lets go through it point by point.

1. OperationContract is decorated with WebGet and URI structure is defined using UriTemplatehttp://localhost:35752/PatientService.svc/Patient/{ID}

below I have given a valid value for {ID}, You can just try running the below URL in any web browser or fiddler copmposer functionality. 

http://localhost:35752/PatientService.svc/Patient/1

Result:

<Patient xmlns="http://schemas.datacontract.org/2004/07/PatientService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<DOB>2011-01-01T00:00:00</DOB>
<Id>1</Id>
<Name>John</Name>
<Place>Floria</Place>
</Patient>

2. In this case we haven't given any spcific URI, so it will take the default URI as method name, 

http://localhost:35752/PatientService.svc/GetAllPatient

Result:

<ArrayOfPatient xmlns="http://schemas.datacontract.org/2004/07/PatientService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Patient>
<DOB>2011-01-01T00:00:00</DOB>
<Id>1</Id>
<Name>John</Name>
<Place>Floria</Place>
</Patient>
<Patient>
<DOB>2014-08-03T00:00:00</DOB>
<Id>3</Id>
<Name>Susane</Name>
<Place>Jordan</Place>
</Patient>
</ArrayOfPatient>

3. Here I have given the parameter as a query param and output format as JSON.

http://localhost:35752/PatientService.svc/Patient?place=Jordan

Result:

[{"DOB":"\/Date(1407004200000+0530)\/","Id":3,"Name":"Susane","Place":"Jordan"}]

4. This OperationContract method is decorated with WebInvoke attribute. Using this I shall add a patient information to the system. To demonstrate this I will be using Fiddler tool.

If you would like to see a reference for this operation then navigate to help section from the service help screen, http://localhost:35752/PatientService.svc/help/operations/AddPatient 

Now lets start using Fiddler to verify the rest service,

As I don't want to see other network traffic details, I'm going to uncheck Capture Traffic from Fiddler-File menu

In Fiddler select Composer tab and enter the service URL, select the Method as POST and also make sure the below points,

  • content-type as application/xml.
  • Request Body as mentioned in the below screenshot

Now click on Execute, Once the request is completed select Web Session to see the result

Click on Inspectors tab to see the result

Our attempt was successful and the service returned the new Id as result of Add operation.

If you execute GetAllPatient method you can see that th data is stored to the database

5. We have already added a new record using Add operation and now we can update that record using Update operation of patient.

after Execute we can see that the operation was successful by checking the Inspectors tab

As expected the data got updated in the database

6. Now I'm going to delete the recently added patient using Delete operation

Click on execute to perform delete

the same way you can write codes for other http verbs.

PatientService

WCF REST Service Implementation

PatientService file contains the actual definition of IPatientService

7. GetPatient method is used to return a single patient details based on the Id parameter.

8. GetAllPatient method is used to return all patient details.

9. GetPatientByPlace method is used to return based on the place parameter.

10. AddPatient is used to add a patient information to the system.

11. UpadatePatient is used to update a patient information from the system.

12. DeletePatient method is used to delete a Patient information 

Web.config

WCF REST Service Web.Config

13. I have created the endpoint by specifying the binding as webHttpBinding

14. Added webHttp behaviour  and enabled help page, so that we can see resample usage of the service.

Code

I have attached the source code with this article. For a quick reference I'm adding the code blocks here.

IPatientService

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

namespace PatientService
{
    [ServiceContract]
    public interface IPatientService
    {
        [OperationContract]
        [WebGet(UriTemplate = "Patient/{id}")]
        Patient GetPatient(string id);

        [OperationContract]
        [WebGet]
        List<Patient> GetAllPatient();

        [OperationContract]
        [WebGet(UriTemplate = "Patient?place={value}", ResponseFormat = WebMessageFormat.Json)]
        List<Patient> GetPatientByPlace(string value);

        [OperationContract]
        [WebInvoke(UriTemplate = "Patient/Add", Method = "POST")]
        int AddPatient(Patient patient);

        [OperationContract]
        [WebInvoke(UriTemplate = "Patient/Update", Method = "PUT")]
        bool UpdatePatient(Patient patient);

        [OperationContract]
        [WebInvoke(UriTemplate = "Patient/Delete/{id}", Method = "DELETE")]
        bool DeletePatient(string Id);
    }
}

PatientService

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

namespace PatientService
{
    public class PatientService : IPatientService
    {
        public Patient GetPatient(string id)
        {
            try
            {
                int patientId = Convert.ToInt32(id);

                using (var db = new PatientInformationEntities())
                {
                    return db.Patients.SingleOrDefault(p => p.Id == patientId);
                }
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        public List<Patient> GetAllPatient()
        {
            try
            {
                using (var db = new PatientInformationEntities())
                {
                    return db.Patients.ToList();
                }
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        public List<Patient> GetPatientByPlace(string value)
        {
            try
            {
                using (var db = new PatientInformationEntities())
                {
                    return db.Patients.Where(p => p.Place == value).ToList();
                }
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        public int AddPatient(Patient patient)
        {
            try
            {
                using (var db = new PatientInformationEntities())
                {

                    db.Patients.Add(patient);
                    db.SaveChanges();

                    return patient.Id;
                }
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        public bool UpdatePatient(Patient patient)
        {
            try
            {
                using (var db = new PatientInformationEntities())
                {

                    Patient oldDetails = db.Patients.SingleOrDefault(p => p.Id == patient.Id);

                    oldDetails.Name = patient.Name;
                    oldDetails.DOB = patient.DOB;
                    oldDetails.Place = patient.Place;

                    db.SaveChanges();

                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        public bool DeletePatient(string id)
        {
            try
            {

                int patientId = Convert.ToInt32(id);

                using (var db = new PatientInformationEntities())
                {

                    Patient details = db.Patients.SingleOrDefault(p => p.Id == patientId);

                    db.Patients.Remove(details);

                    db.SaveChanges();

                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }
    }
}

Web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
      
  <system.serviceModel>
    <services>
      <service name="PatientService.PatientService">
        <endpoint address="" 
                  behaviorConfiguration="restBehavior" 
                  binding="webHttpBinding"  
                  contract="PatientService.IPatientService" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="restBehavior">
          <webHttp helpEnabled="true"/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" 
                               multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
      
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true" />
  </system.webServer>
  <connectionStrings>
    <add name="PatientInformationEntities" 
         connectionString="metadata=res://*/PatientModel.csdl|res://*/PatientModel.ssdl|res://*/PatientModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|\PatientInformation.mdf;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

References

I have added some of the references as a read more link in most of the sections. 

Summary

In this article I have explained REST enabled WCF service with a samples. I hope you have enjoyed this article and got some value addition to your knowledge.

I have put my time and efforts on all of my articles, Please don't forget to mark your votes, suggestions and feedback to improve the quality of this and upcoming articles. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Shemeer NS
Software Developer (Senior)
India India
Technology Specialist | CodeProject MVP | Visual Studio Gallery Contributor | Author | Geek | Netizen | Husband | ChessPlayer
 
Most of my articles are listed on top 5 of the respective 'Best articles of the month' and some of my articles are published on ASP.NET WebSite's Article of the Day section.
 
Check my contributions in Visual Studio Gallery and Code Project
 
Technical Blog: http://www.shemeerns.com
Facebook: http://facebook.com/shemeernsblog
Twitter : http://twitter.com/shemeerns
Google+ : http://google.com/+Shemeernsblog
Follow on   Twitter   Google+

Comments and Discussions

 
GeneralGreat Article. Thanks for the way it is coded and the way it is presented PinmemberAnandKumar R1-Dec-14 2:51 
GeneralMy vote of 5 PinprofessionalChristian Amado12-Sep-14 4:35 
GeneralMy vote of 5 PinmemberMember 108906001-Sep-14 5:56 
QuestionGood article. Few corrections Pinmemberkanreddyjp31-Aug-14 1:02 
GeneralMy vote of 5 PinmemberHumayun Kabir Mamun29-Aug-14 3:37 
QuestionHow about user auth ? PinmemberAlexZhangUS28-Aug-14 15:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141216.1 | Last Updated 28 Aug 2014
Article Copyright 2014 by Shemeer NS
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid