Friday 12 July 2013

WCF REST Based Service Call using JQuery.

Hello friends, I received lot of feedback for my earlier posts. This encourages me to keep writing. Thank you for your feedback.

Ok, let's come back. Today I am going to show you, How to consume WCF REST Service using jQuery.

Problem Scenario:  
Assume we have a page which has three dropdowns to select Country, State and than City. Initially only Country dropdown values will be populated with page load but others will not. On selection of Country, State dropdown values should be populated for the selected country and same for City dropdown. Though the code which I am going to show here is different from the scenario I discussed here but it will help you to solve this kind of problem.

Solution: 
Below sample code shows WCF REST service example which will be consumed through jQuery. Here in my service I have two methods, One returns list of cities as json serialized string object and the other method takes some input (json serialized string) and returns a json serialized string.
Code Sample for Service Definition.:
A
and here the service method implementation.

Note: new JavaScriptSerializer().Serialize(object) is used to convert a object to json serialized object.
Now let's see how we can call to these methods using jQuery.

GET Request
Here we will see, how to make a GET request to call WCF REST based service method GetCities which returns list of city in a json serialized string form. Below is the code sample to do this.

 $.ajax({
        type: "GET", //- Type of request - Optional
        url: 'http://localhost:84/RESTService.svc/cities', //A string containing the URL to which the request is sent.
        dataType: "json", //data type returns from the server
        success: function (response) { //A callback function that is executed if the request succeeds.
            var result = jQuery.parseJSON(response);
            var html = "List of Cities are: <br\>";
            for (var i = 0; i < result.length; i++) {
                if(result[i].Value!="-1")
                    html += result[i].Value + "<br\>";
            }
            $("#div2").html(html);
        },
        error: function (xhr) {
            $("#div2").html("An error occured: " + xhr.status + ':' + xhr.statusText);
        }
    });


Here in above example I specified request type, request url and datatype to the method $.ajax(); Most important thing here is the request url. If url is not found or wcf service is not available in that case it will throw error. So here I also handled error as well. Next if service call is successful then control will fall under success callback function. As we are getting a serialized json object in string form from the server so we need to parse it to json first (because it's a object collection.) and that I am doing here using jQuery.parseJSON() method.
Now we have a json object as result value, shown below:
>> result
[[object Object],[object Object],[object Object],[object Object],[object Object]] {
    [0] : {...},
    [1] : {...},
    [2] : {...},
    [3] : {...},
    [4] : {...},
    [prototype] : []
}

It says we have five Name and Value pair object as per WCF REST Service method. We can access these value by writing code like result[0].Value and result[0].Name.
Important points to take care:
1. Here the Name and Value properties are case sensitive as per the properties definition in WCF REST Service method. So if we write result[0].value to access value then it will not return any value.
2. Another very important point here is, we are parsing the json string directly using response object.
 var result = jQuery.parseJSON(response);
and we have the value of response coming back is:
>> response
"[{"Name":"Select City","Value":"-1"},{"Name":"Bangalore","Value":"Bangalore"},{"Name":"Chennai","Value":"Chennai"},{"Name":"Goa","Value":"Goa"},{"Name":"Delhi","Value":"Delhi"}]"

The point which I want highlight here is, the response json string is not wrapped. Because in the WCF REST Service it is mentioned, not to wrap the response by using below attributes value:
BodyStyle=WebMessageBodyStyle.Bare,. If it would be wrapped then the output string would be bit different as shown below:
>> response
{
    [prototype] : {...},
    GetCitiesResult : "[{"Name":"Select City","Value":"-1"},{"Name":"Bangalore","Value":"Bangalore"},{"Name":"Chennai","Value":"Chennai"},{"Name":"Goa","Value":"Goa"},{"Name":"Delhi","Value":"Delhi"}]"
}

In this case we would have modified few line of code like this:
var result = jQuery.parseJSON(response.GetCitiesResult )
result[0].Name


POST Request
Now we will make a POST request and we will send a json serialized string to WCF REST service method and based on that response will be returned back again as a json serialized string form.
 Let's see the below sample code for POST request:
  var JSONObject = { "userData": { "FName": "Binod", "LName": "Mahto"} };
    $.ajax({
        type: 'POST',
        url: "http://localhost:84/RESTService.svc/Message",
        data: JSON.stringify(JSONObject),
        contentType: "application/json",
        dataType: "json", //Expected data format from server
        processdata: true, //True or False
        success: function (response) {
            $("#div1").html(response.GetWelcomeMessageResult);
        },

        error: function (xhr, ajaxOptions, thrownError) {
            $("#div1").html("An error occured: " + xhr.status + ':' + xhr.statusText);
        }
    });

In above example I mentioned request type as POST. There are few points which we have to take care is:
1. data: which we need to send as POST request should be json serialized string form. Which we are doing here using JSON.stringify() method.
2. content type: It must be "application/json". Instead of this if we write only "json" it will throw error as "400:Bad Request".
3.  datatype: It must be "json" only. Instead of this if we write "application/json" then it will throw error by saying "200:OK" but surprisingly error object 'xhr' will have the response output as well.
>> xhr
{
    [Methods] : {...},
    [prototype] : {...},
    readyState : 4,
    responseText : "{"GetWelcomeMessageResult":"\"Hi Binod Mahto Current time is:10:12 AM\""}",
    status : 200,
    statusText : "OK"
}

So to avoid this kind of head banging issue datatype's value must be written as "json" only.
4. Response output is wrapped here. If you see the response output here, you will find there is name attached with response string as "GetWelcomeMessageResult". And this happened because in the WCF REST method specifically it is mentioned to wrap the response object (by using attribute value BodyStyle = WebMessageBodyStyle.Wrapped). And the catch here is, the extra string which will be added to json string will have concatenation string of method name and 'Result' string. for Ex: GetWelcomeMessageResult. 
5. Another important thing here is that when you send the json serialized object (as I am sending userData here) to the server then it must be wrapped with the exact parameter name mentioned in the WCF REST service method.
 var JSONObject = { "userData": { "FName": "Binod", "LName": "Mahto"} };
In my case here my WCF REST Service method expects UserData object as per data contract.
    [DataContract]
    public class UserData
    {
        [DataMember]
        public string FName { get; set; }

        [DataMember]
        public string LName { get; set; }
    }
  

and the parameter name in service method is mentioned as "UserData userData". So suppose if I change my JSONObject value as 
var JSONObject = { "UserData": { "FName": "Binod", "LName": "Mahto"} };  then WCF Service method will be called but userData parameter value will be null. So we should keep this in mind that parameter name is tightly coupled with the json request format.

I guess I mentioned all the important points here for which generally people has to struggle a lot. But still if I missed something please feel free to mention those as your comment/feedback.

Thank You 

3 comments: