Friday, April 1, 2011

Javascript Deserialization Error Converting Ajax JSON in ASP.Net Web Service

fast light wave runner - like jQuery ajaxThe .Net framework makes it very easy to do fast lightweight AJAX calls to an ASP.Net web service using jQuery or other frameworks using json (JavaScript Object Notation) and XMLHTTPRequest (MUCH faster and lighter weight than the UpdatePanel).

Because the data in json is delimited by apostrophe’s, having them within the text (as the data itself) can throw a deserializing error when ASP.Net parses the json text body into the web service method parameters. A simple way to prevent is to wrap your javascript variable with the escape() method. It will convert an apostrophe to %u2019. On the server side within your web method before you pass the data to the database, you can wrap it with Server.UrlDecode() to convert it back to an apostrophe.

Javascript jQuery Ajax call

Below is an example of a typical jQuery asynchronous call to a web service. Note the webservice name is AppWebService.asmx. UpdateComments is the web method being called. The UpdateComments web method takes two parameters an integer RecordID and a string RecordComments. Note the use of escape(RecordComments) to encode the RecordComments field in the event that it contains apostrophes (or other special characters).

var options = {
    type: "POST",
    url: "/Application/AppWebService.asmx/UpdateComments",
    data: "{'RecordID':" + RecordID + ", 'RecordComments':'"
        + escape(RecordComments) + "'}",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (response) {
        if (response.d == "") {
            jQuery('#saving').hide();
        }
    }, //end success
    error: function (response) {
        alert("Sorry, the update failed. \n\n Details follow: " 
    + response.responseText);
    } //end error
};
 
//Call the Web service
jQuery.ajax(options);

 

Raw Request Captured in Fiddler


slow ferry boat - like full page postback or UpdatePanelThe text below is the contents of the HTTP request that is sent to the web service. In this case the actual data is much smaller than the request header information. You can see how much less data is being sent back to the server for processing compared with a complete page postback or even an ASP.Net AJAX UpdatePanel. The json data itself is:


{'RecordID':10629, 'RecordComments':'cat%u2019s%20meow'}


The RecordComments text is an encoded version of “cat’s meow” (without the quotes).


POST http://domain/Application/AppWebService.asmx/UpdateComments HTTP/1.1
x-requested-with: XMLHttpRequest
Accept-Language: en-us
Referer:
http://domain/Application/RecordMaintenance.aspx
Accept: application/json, text/javascript, */*
Content-Type: application/json; charset=utf-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0
Host: kestrel
Content-Length: 148
Connection: Keep-Alive
Pragma: no-cache


{'RecordID':10629, 'RecordComments':'cat%u2019s%20meow'}


Web Method accepts json


Behind the scenes ASP.Net parses the json data and uses it to populate the web method parameters. If there was an apostrophe in the json text body as shown below:


{'RecordID':10629, 'RecordComments':'cat's meow'}


ASP.Net would not correctly parse the data correctly, because it would be expecting a closing bracket } immediately after 'cat'. Since we escaped the data, it is parsed correctly using the following web method. Note the use of Server.URLDecode to convert the RecordComment from “cat%u2019s%20meow” back to “cat's meow” before passing it to the helper method as a parameter for a stored procedure.



<WebMethod()> _
<ScriptMethod()> _
Public Function UpdateComments(ByVal RecordID As Integer, ByVal RecordComments As String) As String
 
    Dim result As String = String.Empty
    Try
        CommonSQL.ExecuteNonQuery("sproc_name", _
           RecordID, _
           Server.UrlDecode(RecordComments))
 
    Catch ex As Exception
        Return ex.ToString
    End Try
 
    Return result
End Function

 


photo credit (wave runner): db2r / cc BY-SA 2.0

No comments: