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 :)

3 comments:

Nico said...

The EventArgs of XXXCompleted has an "Error" property which encapsulates the exception trown by the WebService.
You can check if Error is not null to "catch" that exception.

.:: m3rLinEz ::. said...

Thanks nico, I had tried using that method too but the "TargetInvocationException" raised in another thread still not caught.

Anonymous said...

Hi, I didn't have to change my code to using BackgroundWorker.

I still can happily call XXXAsync and handling the TargetInvocationError msg.

See:
http://geeks.netindonesia.net/blogs/zeddy/archive/2008/08/21/how-to-resolve-targetinvocationexception-error-catching-exception-in-asynchronous-calls.aspx