Showing posts with label web service. Show all posts
Showing posts with label web service. Show all posts

Monday, December 18, 2006

How to consume UrbanDictionary service with Java Script

From my last entry, I had wrote that my instructor assign a project on mashing-up three web services together. Today I had to help my friend who need to consume a service from UrbanDictionary, a slang dictionary, using SOAP and JavaScript.

Actually there is an example of how to consume a service with JavaScript on their website too. However, it is still hard for a complete JavaScript newbies to understand and use.

So I had to code the skeleton part for my friend. Here is the code

function lookup(key, word) {
req = new XMLHttpRequest();
req.open("POST", "http://api.urbandictionary.com/soap", true);
req.onreadystatechange = function() {
if (req.readyState == 4) {
var results = req.responseXML.getElementsByTagName("item");
var len = results.length;
var resp = "";
for(var i = 0 ; i < len ; i++)
{
var item = results[i];
for(var j = 0 ; j < item.childNodes.length ; j++)
{
var node = item.childNodes[j];
resp+="<br />";
if(node.nodeName == "word")
resp+= "คำว่า : " + node.firstChild.data;
else if(node.nodeName == "definition")
resp+= "คำจำกัดความ : " + node.firstChild.data;
else if(node.nodeName == "author")
resp += "ผู้แต่ง : " + node.firstChild.data;
else if(node.nodeName == "url")
resp += "URL : " + node.firstChild.data;


}
resp += "<hr />";
}
spanResp.innerHTML = resp;
}
}

var post = '<?xml version="1.0" encoding="UTF-8"?>' +
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
'<soapenv:Body>' +
'<ns1:lookup soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:UrbanSearch">' +
'<key xsi:type="xsd:string">' + escape(key) + '</key>' +
'<term xsi:type="xsd:string">' + escape(word) + '</term>' +
'</ns1:lookup>' +
'</soapenv:Body>' +
'</soapenv:Envelope>';

req.setRequestHeader('Content-Type', 'text/xml');
req.send(post);
}

function doLookUp()
{
var oTxt = document.getElementById('txtWord');
lookup('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', oTxt.value);
}

You have to replace "xxxxxxxxxxxxxx" with your UrbanDictionary passkey to get this code working.

One of the problem I encountered during coding this example is the "getElementsByTagName" method. I first use the "getElementByTagName" (no 's' in 'Element') method which does not exist. It takes me a while to figure this out.

Wednesday, December 13, 2006

Handling exceptions in asynchronous web service call in Visual Studio 2005


I had just finish developing my application for ISO (Information System Organization - one of the subject teached at my university). The requirements are to consume 3 of the services available at http://www.programmableweb.com/matrix and the students can develop their applications for any available platforms. I choose to develop my project, MashOpedia, on the .NET Framework 2.0 using Visual C# Express Edition as my IDE.

Consuming web services with Visual Studio is sure an easy job for those services which provide WSDLs. In Visual Studio .NET 2003, any method exposed from a generated proxy classes have their asynchronous versions whose names are "BeginXXX" and "EndXXX" where "XXX" is original method's name. These methods allow the developers to call web services in asynchronous style easily!

However, when you generated a proxy classes with Visual Studio 2005 there are no these "BeginXXX" and "EndXXX" methods anymore. You will find "XXXAsync" method and "XXXCompleted"event instead. These provide an easier way to invoke a web service in asynchronous style. You first call "XXXAsync" and when the call is completed it will raise "XXXCompleted" event.

I had used the "XXXAsync" method to call web serice in my project. But one problem arises. How do I handle those exceptions generated in another thread ?. In Visual Studio .NET 2003 I can wrap the try..catch block over the "EndXXX" method call. Any exception, such as SocketException caused by internet connectivity problem, would be caught by this block.

But in Visual Studio 2005,


void serv_doGoogleSearchCompleted(object sender, doGoogleSearchCompletedEventArgs e)
{
if (e.Error != null)
MessageBox.Show(e.Error.Message);
...
}

I can detect if there is an error occurred in asynchronous call but I could not handle it. When I intentionally unplug my LAN connection. The program stop working and push me back to the IDE with the mysterious "TargetInvocationException" at line "Application.Run(...)". I dont know how should I handle such case. I try wrap the try..catch block around "Application.Run(...)" too. That works but the form instantly close itself after the exception is catched which is not what I want.

One workaround I used to solve this problem is to wrap a synchronous call within the BackgroundWorker. This allows me to call the web service in asynchronous style (The GUI is not freezed) and allows me to handle exceptions raise by the call too.

private void backgroundSearch_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = null;
try
{
GoogleSearchService googleSearch = new GoogleSearchService();
GoogleSearchResult googleRes = googleSearch.doGoogleSearch(ApplicationSettings.GoogleLicenseKey,
txtKeywords.Text, 0, 10, true, "", false, "", "", "");
...
}
catch (Exception ex)
{
e.Result = ex;
}

}

private void backgroundSearch_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result == null)
{
/* Means operation completed successfully */
...
}
else
{
/* Failed */
...
}

If there is more simple way to solve this problem, feel free to tell me :)