SYSK 217: Processing WebService Response using JSON
For those of you who haven’t done much work with JSON, this blog may be a good introduction...
JSON stands for JavaScript Object Notation (pronounced ‘Jason’) and is a lightweight data-interchange format with smaller footprint than xml, human readable (just like xml), simple language model supported by the following languages: ActionScript, C, C#, ColdFusion, E, Java, JavaScript, Lua, ML, Objective CAML, Perl, PHP, Python, Rebol, and Ruby.
The popularity of JSON is largely due to its simplicity, more compact footprint (compared to xml) and the fact that JSON can be accessed across domains by dynamically creating script tags, which is handy for mash-ups.
The rules are very simple (http://www.json.org/):
1. Objects start with { and end it with }
2. Object members (properties) are contained within {}
3. Members are represented by two strings – name and value separated by :
4. A value can be a string, number, object, array, true, false, null
5. To create an array of objects, use []
Here is a JSON string example:
{
"books":
[
{"book":
{
"title":"The Elegant Universe",
"author":"Brian Greene",
"ISBN":"0-375-70811-1"
}
},
{"book":
{
"title":"Nanotechnology: A Gentle Introduction to the Next Big Idea",
"author":"Mark Ratner and Danial Ratner",
"ISBN":"0-13-101400-5"
}
},
{"book":
{
"title":"A Short History of Nearly Everything",
"author":"Bill Bryson",
"ISBN":"0-7679-0817-1"
}
}
]
}
JSON’s eval() function parses the JSON string returns a javascript object, and it is quite fast.
NOTE: The eval() function can be unsafe as there is no guaranty that the string doesn’t contain some functions that, execute by the browser, could cause damage. See http://www.json.org/js.html. To keep the sample easy to follow, I’m omitting handling this problem.
Now, let’s create a web service in C# 2.0 with the following web method:
[WebMethod]
public string GetGreatBooks()
{
return "{\"books\":[{\"book\":" +
"{" +
"\"title\":\"The Elegant Universe\"," +
"\"author\":\"Brian Greene\"," +
"\"ISBN\":\"0-375-70811-1\"" +
"}" +
"}," +
"{\"book\":" +
"{" +
"\"title\":\"Nanotechnology: A Gentle Introduction to the Next Big Idea\"," +
"\"author\":\"Mark Ratner and Danial Ratner\"," +
"\"ISBN\":\"0-13-101400-5\"" +
"}" +
"}," +
"{\"book\":" +
"{" +
"\"title\":\"A Short History of Nearly Everything\"," +
"\"author\":\"Bill Bryson\"," +
"\"ISBN\":\"0-7679-0817-1\"" +
"}" +
"}" +
"]}";
}
On the HTML page (code below), we have a button which, when clicked would invoke a web service using XmlHttpRequest. Once the web service returns the JSON string above, the following code is executed:
var myOnComplete = function(responseText, responseXML)
{
// getText strips off the xml stuff added by web method
// and returns just JSON string
var r = eval('(' + getText(responseText) + ')');
var e = document.getElementById('GreatBooks');
e.innerHTML = "<h3>Great Books</h3>";
for (var i = 0; i < r.books.length; i++)
{
e.innerHTML += (i+1) + "). <b>" + r.books[i].book.title +
"</b> by " + r.books[i].book.author +
" (ISBN " + r.books[i].book.ISBN + ")<br>";
}
}
Here is the complete source for the web page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Test Page</title>
<script type="text/javascript">
{
// TODO: In production apps, replace alert with less invasive method
function WebServiceProvider()
{
var me = this;
var request = null;
var prevUrl = "";
var inProgress = false;
var isComplete = false;
// call this function to call a web service
this.invokeService = function(url)
{
if (IsBusy())
{
alert("Busy processing another request " + prevUrl);
}
else
{
prevUrl = url;
inProgress = true;
isComplete = false;
if (window.XMLHttpRequest)
{
// XMLHttpRequest object supported by browser
request = new XMLHttpRequest();
request.onreadystatechange = onRequestComplete;
request.open("GET", url, true);
request.send(null);
}
else
{
// IE uses an ActiveX control as XMLHTTP implementation
if (window.ActiveXObject)
{
request = new ActiveXObject("Microsoft.XMLHTTP");
if (request != null)
{
request.onreadystatechange = onRequestComplete;
request.open("GET", url, true);
request.setrequestheader("Pragma","no-cache");
request.setrequestheader("Cache-control","no-cache");
request.send();
}
else
{
alert("Unable to create Microsoft.XMLHTTP");
}
}
else
{
alert("Browser does not support XML HTTP Request");
}
}
}
} // end invokeService
// Only one request at a time allowed
var IsBusy = function()
{
return inProgress && !isComplete;
}
var onRequestComplete = function()
{
var STATE_COMPLETED = 4;
var STATUS_200 = 200;
if (request != null)
{
if (request.readyState == STATE_COMPLETED)
{
inProgress = false;
isComplete = true;
if (request.status == STATUS_200)
{
if (me.onComplete)
me.onComplete(request.responseText, request.responseXML);
}
else
{
alert("Error " + request.status + " invoking " + prevUrl);
}
}
}
}
// A way for callers of this function to override this method
var onComplete = null;
this.onComplete = function(responseText, responseXML)
{
}
} // end function WebServiceProvider
function CallWS()
{
// strip off xml stuff returned by a web method
var getText = function(xml)
{
var xmlDoc;
if (document.implementation && document.implementation.createDocument)
xmlDoc = document.implementation.createDocument("", "", null);
else if (window.ActiveXObject)
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
else
{
alert('Browser does not support XML documents');
return;
}
xmlDoc.async = false;
xmlDoc.loadXML(xml);
return xmlDoc.documentElement.text;
}
// XMLHttpRequest completion function
var myOnComplete = function(responseText, responseXML)
{
var r = eval('(' + getText(responseText) + ')');
var e = document.getElementById('GreatBooks');
e.innerHTML = "<h3>Great Books</h3>";
for (var i = 0; i < r.books.length; i++)
{
e.innerHTML += (i+1) + "). <b>" + r.books[i].book.title +
"</b> by " + r.books[i].book.author +
" (ISBN " + r.books[i].book.ISBN + ")<br>";
}
}
var provider = new WebServiceProvider();
provider.onComplete = myOnComplete;
provider.invokeService("http://localhost:2288/WebSite1/BookService.asmx/GetGreatBooks");
}
}
</script>
</head>
<body style="font-size: 0.8em; font-family:Verdana;">
<input type="button" value="Click here to get names of great books..." onclick="javascript:CallWS();" />
<div id="GreatBooks"></div>
</body>
</html>
Comments
- Anonymous
February 07, 2007
Say, you have to pass in a large number of data elements into a web service (to me, more than 5 is “many”).