You are on page 1of 12

simple WCF REST Service example. Here are summarized steps.

(1) Run Visual Studio


(2) New Project - WCF - [WCF Service Application]
(3) Delete IService1.cs and Service1.svc
(4) Add New Item - [WCF Service] item. Name it SimpleRestService.svc.
(5) Write WCF RESTful interface in ISimpleRestService.cs.
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace SimpleWcfRESTService
{
[ServiceContract]
public interface ISimpleRestService
{
[OperationContract]
[WebGet(UriTemplate="Test")]
string DoTest();
[OperationContract]
[WebGet(UriTemplate = "CustomerName/{id}")] // URI param is
always string type
string GetCustomerName(string id);
[OperationContract]
[WebGet(UriTemplate = "Customer/{id}", BodyStyle =
WebMessageBodyStyle.Bare)]
Customer GetCustomer(string id);
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "Customer",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml)]
// Default request format is XML
// Should set Content-Type: application/xml in req. header
bool AddCustomer(Customer cust);
[OperationContract]
[WebInvoke(Method="PUT", UriTemplate="Customer/{id}", BodyStyle
= WebMessageBodyStyle.Bare)]
bool UpdateCustomer(string id, Customer cust);
[OperationContract]

[WebInvoke(Method = "DELETE", UriTemplate = "Customer/{id}")]


bool DeleteCustomer(string id);
}
[DataContract(Namespace="")]
public class Customer
{
[DataMember]
public int Id;
[DataMember]
public string Name;
[DataMember]
public string Address;
}
}

(6) Write WCF REST service class that implements the interface.
namespace SimpleWcfRESTService
{
public class SimpleRestService : ISimpleRestService
{
public string DoTest()
{
return "Testing SimpleRestService...";
}
public string GetCustomerName(string id)
{
Customer c = DBProcessor.GetCustomer(id);
return c.Name;
}
public Customer GetCustomer(string id)
{
return DBProcessor.GetCustomer(id);
}
public bool AddCustomer(Customer cust)
{
return DBProcessor.AddCustomer(cust);
}
public bool UpdateCustomer(string id, Customer cust)
{

return DBProcessor.UpdateCustomer(id, cust);


}
public bool DeleteCustomer(string id)
{
return DBProcessor.DeleteCustomer(id);
}
}
}

For persist mechanism, the example uses a helper class for database processing. This
persist mechanism is not the focus of the example, here is an example for simple db
processing. Assume we have a DBCustomer table (has Id,Name,Address columns) in SQL
and we created LINQ to SQL .dbml for the table. For testing, add a few sample data.
using System.Linq;
namespace SimpleWcfRESTService
{
public class DBProcessor
{
static DataClasses1DataContext db = new
DataClasses1DataContext();
public static Customer GetCustomer(string id)
{
int cid = int.Parse(id);
var dbCust = db.DBCustomers.SingleOrDefault(p => p.Id ==
cid);
Customer cust = new Customer();
if (dbCust != null)
{
cust.Id = dbCust.Id;
cust.Name = dbCust.Name;
cust.Address = dbCust.Address;
}
return cust;
}
public static bool AddCustomer(Customer cust)
{
try
{
DBCustomer dbCust = new DBCustomer
{
Id = cust.Id,
Name = cust.Name,

Address = cust.Address
};
db.DBCustomers.InsertOnSubmit(dbCust);
db.SubmitChanges();
}
catch
{
return false;
}
return true;
}
public static bool UpdateCustomer(string id, Customer cust)
{
try
{
int cid = int.Parse(id);
var dbCust = db.DBCustomers.SingleOrDefault(p => p.Id ==
cid);
dbCust.Name = cust.Name;
dbCust.Address = cust.Address;
db.SubmitChanges();
}
catch
{
return false;
}
return true;
}

public static bool DeleteCustomer(string id)


{
try
{
int cid = int.Parse(id);
var dbCust = db.DBCustomers.SingleOrDefault(p => p.Id ==
cid);
db.DBCustomers.DeleteOnSubmit(dbCust);
db.SubmitChanges();
}
catch
{
return false;
}

return true;
}
}
}

(7) Update web.config - use webHttpBinding for REST service and add REST (webHttp)
endpointBehavior.
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="TestDBConnectionString" connectionString="Data
Source=.;Initial Catalog=TestDB;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="SimpleWcfRESTService.SimpleRestService">
<endpoint address="" binding="webHttpBinding"
behaviorConfiguration="REST"
contract="SimpleWcfRESTService.ISimpleRestService">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value
below to false and remove the metadata endpoint above before deployment
-->
<serviceMetadata httpGetEnabled="true"/>
<!-- 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>

<!-- If REST behavoir is not specified, the following error


occurs:
The message with To
'http://localhost/SimpleRest/SimpleRestService.svc/test' cannot be
processed at the receiver,
due to an AddressFilter mismatch at the EndpointDispatcher.
Check that the sender and receiver's EndpointAddresses agree.-->
<endpointBehaviors>
<behavior name="REST">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>

(8) IIS hosting - we can create a new Site for the REST service. But in this example, we add
a new Web Application called SimpleRest under the Default Web Site (port 80). So the REST
service can be accessed at http://localhost/SimpleRest/SimpleRestService.svc. (Run VS as
an Administrator and publish REST service by using [Build] - [Publish Service] menu.)

(9) Once the REST service is published to Default Web Site, try a simple test URL in web
browser.
http://localhost/SimpleRest/SimpleRestService.svc/test
(10) Now try to get data from database.
http://localhost/SimpleRest/SimpleRestService.svc/CustomerName/1
We got an error this time. When checking SQL Server error log, the failure is obvious. This is
because by default [Default Web Site] application pool uses IIS APPPOOL\DefaultAppPool
account but SQL does not include the account.
Login failed for user 'IIS APPPOOL\DefaultAppPool'. Reason: Token-based
server access validation failed with an infrastructure error

So either add this account (IIS APPPOOL\DefaultAppPool) to SQL logins or use different
account for DefaultAppPool application pool. For test purpose, we can simply change IIS
App Pool account to Network Service (How to: IIS manager - [Application Pools] - Click
[DefaultAppPool] - Click [Advanced Settings] - Change [Identity]. Once it is changed and

restart app pool, the URL above should give Name for customer id = 1.

(11) HTTP GET url can be tested in web browser but if we want to send some data to REST
service via POST or PUT, we write REST clent program, AJAX in html or use utility tool such
as Fiddler. To write REST client program, we could use various APIs such as HttpClient
(REST Starter Kit), WCF WebChannelFactory, HttpWebRequest, WebClient. But here let's
use Fiddler tool.

In order to test [Add Customer], in Fiddler, go to Composer and select POST method and
type url http://localhost/SimpleRest/SimpleRestService.svc/Customer
In request header, type Content-Type: application/xml and type data below in Request Body.
Click [Execute] then the data will be inserted into DB.
<Customer><Address>Bellevue
WA</Address><Id>10</Id><Name>Tom</Name></Customer>
Please note that we add field data in Address/ID/Name order. If you specify the data in
ID/Name/Address as specified in DataContract, Address will be null. This is because the
default order of DataContract serialization/deserialization is alphabetical. (This order can be
changed by specifying Order in DataMember attribute)
(12) HTTP PUT is similar to POST. So it is needed to fill in Request Body with data. HTTP
DELETE is similar to GET since the method prototype only requires Id.
Here are some examples for HTTP GET/POST/PUT/DELETE requests in Fiddler.

(13) How to use JSON


Instead of XML as a request input or response output, we can use simpler JSON format.
Default request/response message format is XML, so if we want to use JSON, we have to
set RequestFormat and/or ResponseFormat to JSON. For example, we can define new URI
[Customer/json] to use JSON input and output.
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "Customer/json",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
Customer AddAndReturnCustomer(Customer cust);
And a simple implementation code is:
public Customer AddAndReturnCustomer(Customer cust) {
bool success = DBProcessor.AddCustomer(cust);
return cust;

In order to use JSON from Fiddler, we set Content-Type to application/json and put json
format input in request body as seen below. Response will be also JSON format as we set
ResponseFormat to Json in WebInvoke attribute.

You might also like