Consuming WCF REST services using JQuery and C#


The objective of this post is to demonstrate how WCF RESTful services can be used to perform CRUD operations against a data source and then consume it using a JavaScript as well as a .NET client using C#.

Assuming you have a WCF service configured to use the webHttpBinding, you could have operations defined as shown below that allows you to Create, Read, Update and Delete a particular record (in this example a record from the Category table in the Northwind database).

//Returns a list of Categories

[WebGet(ResponseFormat=WebMessageFormat.Json)]


public
List<Category> GetCategories()

{


NorthwindDataContext northwind = new
NorthwindDataContext();


var q = northwind.Categories;


return q.ToList();

}

The WebGet attribute will allow an HTTP GET request to be made to invoke this operation. Because we haven’t specified any UriTemplate for this operation, the url to which the GET request will have to be made will be something like – http://server:port/Service1.svc/GetCategories. Also thanks to the ResponseFormat attribute, the list of categories will be sent in JSON format.

The next operation returns just one single Category object.


//Returns an individual category object

[WebGet(UriTemplate=“Get/Category/{id}”, ResponseFormat=WebMessageFormat.Json)]


public
Category GetCategory(string id)

{


NorthwindDataContext northwind = new
NorthwindDataContext();


var category = northwind.Categories.FirstOrDefault(c=> c.CategoryID == Convert.ToInt32(id));


return category;

}

This time since we have specified an UriTemplate, the url to retrieve the category for categoryid=2 will be something like – http://server:port/Service1.svc/Get/Category/5. The placeholder {id} in the url matches the string input parameter of this method. Note that even though I would’ve wanted to change the data type of the input parameter to an int, I have to specify it as a string.

The next operation allows us to make an HTTP GET request and pass the categoryid of the category we want to delete.

//Deletes a category

[WebGet(UriTemplate = “/Delete/Category/{id}”, ResponseFormat=WebMessageFormat.Json)]


public
bool DeleteCategory(string id)

{


try

{


NorthwindDataContext northwind = new
NorthwindDataContext();


Category category = northwind.Categories.FirstOrDefault(c => c.CategoryID == Convert.ToInt32(id));

northwind.Categories.DeleteOnSubmit(category);

northwind.SubmitChanges();


return
true;

}


catch (Exception)

{


return
false;

}

}

The next operation is slightly different from the others defined so far. It doesn’t take in a primitive value (like a string) as an input parameter. Instead it takes in a complex type like a Category object as an input parameter. Also since a complex object cannot be passed thru the querystring, this time we use the WebInvoke attribute instead of WebGet. WebInvoke by default, allows an HTTP POST request to be made to invoke the operation. Since we have specified the RequestFormat attribute to be JSON, the category object will have to be sent in that format (the default being XML).


//Adds a new category.

[WebInvoke(UriTemplate=“/Add/Category”, RequestFormat=WebMessageFormat.Json, ResponseFormat=WebMessageFormat.Json)]


public
bool AddCategory(Category category)

{


try

{


NorthwindDataContext northwind = new
NorthwindDataContext();

northwind.Categories.InsertOnSubmit(category);

northwind.SubmitChanges();


return
true;

}


catch (Exception)

{


return
false;

}

}

Lastly the EditCategory operation allows an existing category to be modified and it is very similar to the previous Add operation with nothing new to discuss.

[WebInvoke(UriTemplate=“/Edit/Category”, RequestFormat=WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]


public
bool EditCategory(Category category)

{


try

{


NorthwindDataContext northwind = new
NorthwindDataContext();


var categoryFromDB = northwind.Categories.FirstOrDefault(c => c.CategoryID == category.CategoryID);

categoryFromDB = category;

northwind.SubmitChanges();


return
true;

}


catch (Exception)

{


return
false;

}

}

Before moving on to building the client application to consume this service, it would be a good idea to test some of these operations in the browser and verify that they are working as expected.

The Client

To consume this RESTful service, I started off with a new HTML page and added the following markup


<form>


<h2>Categories</h2>


<ul
id=”Categories”></ul>


<p></p>


<label
for=”Category ID”>Category ID &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : </label>


<input
type=”text” id=”txtCategoryID” style=”width:75px”
/>


<br />


<label
for=”txtCategoryName”>Category Name :</label>


<input
type=”text” id=”txtCategoryName”
/>


<br />


<label
for=”txtDescription”>Description &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :</label>


<input
type=”text” id=”txtDescription” style=”width:400px”
/>


<p></p>


<input
type=”button” id=”btnEdit” value=”Save Changes”
/>



<input
type=”button” id=”btnAdd” value=”Add new Category”
/>


<input
type=”button” id=”btnDeleteCategory” value=”Delete Category”
/>


<p></p>


<span
id=”spnStatus”></span>


</form>

To make the JavaScript programming easier, I added the JQuery and the JSON2.js files to the page.


<script
src=”Scripts/jquery-1.7.2.js” type=”text/javascript”></script>


<script
src=”Scripts/json2.js” type=”text/javascript”></script>

In another <script> tag, I added a global variable called url which points to the relative url of my web service and an event handler for the document ready event.


<script
type=”text/javascript”>


var url = ‘Service1.svc/’;

$(document).ready(function () {

GetAllCategories();

     });

The implementation of the GetAllCategories method is as follows –


function GetAllCategories() {


//clear the previous values in some html elements

$(‘spnStatus’).html();

$(‘#Categories li’).remove();

$(‘#txtCategoryID’).val();

$(‘#txtCategoryName’).val();

$(‘#txtDescription’).val();


//Call the GetCategories method in the service

$.getJSON(url + “GetCategories”, null, function (data) {


for (var i = 0; i < data.length; i++) {

$(‘#Categories’).append(“<li><a href=javascript:GetCategory(“ + data[i].CategoryID + “)>” + data[i].CategoryName + “</a></li>”);

}

});

}

The JQuery getJSON method makes an HTTP GET request to the Service1.svc/GetCategories url. The second parameter is any data that you want to pass along with the request (in this case, null). The third parameter is the callback function that gets invoked whenever the request completes. Since we are using the getJSON method, the output received from the webservice is automatically serialized and parsed as a JSON object without any further intervention from us. All I do here is iterate thru all the categories returned and add each one as a li (listitem) to the ul (unordered list).

The html page is initially rendered as follows –

The anchor tag of each category has been set to call a function called GetCategory. The implementation of the function is as follows.


function GetCategory(categoryid) {


//Call the GetCategory method in the service

$.getJSON(url + “Get/Category/” + categoryid, null, function (data) {


if (data == null) {

$(‘#spnStatus’).html(‘category not found’);

}


else {


//populate the html elements with various property values

$(‘#txtCategoryID’).val(data.CategoryID);

$(‘#txtCategoryName’).val(data.CategoryName);

$(‘#txtDescription’).val(data.Description);

}

});

}

In this function we use the same getJSON method to make a HTTP GET request to Service1.svc/Get/Category/{id} url. The category object returned by the service will be automatically parsed as a JSON object and we can just use various properties like CategoryID and CategoryName to bind it to various textboxes.

With a particular category now displayed, we can now click on the Delete Category button to delete it. The Delete Category button’s click event is wired up as follows (in the document ready event handler) –

$(‘#btnDeleteCategory’).click(function () {

$.getJSON(url + “Delete/Category/” + $(‘#txtCategoryID’).val(), null, function (data) {


if (data) {

$(‘#spnStatus’).html(‘category sucessfully deleted’);

GetAllCategories();

}


else

$(‘#spnStatus’).html(‘category could not be deleted’);

});

});

This function continues to make an HTTP GET request to a URL, passing the category id that needs to be deleted as part of the URL.

The Add new category and Save Changes button technically do the same thing; hence only one of them is discussed here. The implementation of the Add Category button is as shown below –

$(‘#btnAdd’).click(function () {


//construct a category object


var category = {

CategoryName: $(‘#txtCategoryName’).val(),

Description: $(‘#txtDescription’).val()

};


//use JSON API to convert the object as a string


var s = JSON.stringify(category);


var request = $.ajax(url + “Add/Category”, {

type: “POST”, // POST Request

data: s, // stringified version of Category object

dataType: “json”, // output returned by the service should be converted to json format

contentType: “application/json; charset=utf-8”

}).done(function (data) {


// success callback

GetAllCategories();

$(‘#spnStatus’).html(‘category sucessfully added’);

}).fail(function (data) {


// failure callback

$(‘#spnStatus’).html(‘category could not be added’);

});

});

The function first constructs a new Category object and populates its various properties. CategoryID is left out since it is set as an identity column in the database. Since we are supposed to be passing input to the service in the form of a JSON object, we have to take the Category object and convert it to a JSON formatted object. The JSON.stringify method does that. Then we use JQuery’s ajax method to invoke the service. We can’t use the getJSON method we had used previously because we now need to make a POST request instead of a GET request. We could have used the post method, however the post method does not allow us to change the contentType. The default contentType used is ‘application/x-www-form-urlencoded; charset=UTF-8’, which will not work with our web service. The done and fail methods finally allow us to specify the success and failure callback functions.

To add a new Category, fill up the relevant details and click on the “Add new Category” button.

Intercepting the request in a tool like Fiddler allows me to view the raw HTTP Request and Response headers. The request looks as follows –

The response returned by the web service looks like this –

Now that I can see the raw input and output, it would be very easy to perform the same operation using C# code instead of JavaScript.

The following C# code makes a HTTP POST request to add a new category object. The Category object needs to be constructed carefully. It needs to be like this –

{“CategoryName”:”Bakery Products”,”Description”:”Breads, crackers, pasta, and cereal”}

And not like this

{‘CategoryName’:’Bakery Products’,’Description’:’Breads, crackers, pasta, and cereal’}


//the category object in JSON format


string postData = “{\”CategoryName\” : \”Test from .NET\”, \”Description\” : \”This category was inserted from a C# application\”}”;


//convert the data as a byte array


byte[] byteArray = Encoding.UTF8.GetBytes(postData);


//create an HTTP request to the URL that we need to invoke


HttpWebRequest request = (HttpWebRequest)WebRequest.Create(http://localhost:49779/Service1.svc/Add/Category&#8221;);

request.ContentLength = byteArray.Length;

request.ContentType = “application/json; charset=utf-8”; //set the content type to JSON

request.Method = “POST”; //make an HTTP POST


using (Stream dataStream = request.GetRequestStream())

{


//initiate the request

dataStream.Write(byteArray, 0, byteArray.Length);

}


// Get the response.


WebResponse response = request.GetResponse();

All these examples used a web service which was expecting data in JSON format. If you plan to invoke these operations using JavaScript, then JSON will definitely be the format of choice. But if you are using C# or any other language other than JavaScript to interact with the service, you may prefer to work with XML instead of JSON. If that’s the case, change the signature of the AddCategory method as follows –

The C# code would change in just two places. Instead of creating a JSON representation of our object, we will need to create an XML representation. Secondly the contentType property of the HTTPRequest object would change to application/xml. The final code would be –


//category object in XML format


string postData =


“<Category xmlns=’http://schemas.datacontract.org/2004/07/WebApplication1&#8242; xmlns:i=’http://www.w3.org/2001/XMLSchema-instance’>&#8221; +


“<CategoryName>Bakery Products</CategoryName>” +


“<Description>Breads, crackers, pasta, and cereal</Description>” +


“</Category>”;


byte[] byteArray = Encoding.UTF8.GetBytes(postData);


//create an HTTP request to the URL that we need to invoke


HttpWebRequest request = (HttpWebRequest)WebRequest.Create(http://localhost:49779/Service1.svc/Add/Category&#8221;);

request.ContentLength = byteArray.Length;

request.ContentType = “application/xml”; //set the content type to XML

request.Method = “POST”; //make an HTTP POST


using (Stream dataStream = request.GetRequestStream())

{


//initiate the request

dataStream.Write(byteArray, 0, byteArray.Length);

}


// Get the response.


WebResponse response = request.GetResponse();

So that’s it. That’s how a RESTful service can be invoked using both JavaScript as well as C#.