The uncatchable exceptions in WCF clients

Did you ever have a problem with a WCF client throwing exceptions you can't catch?

If you have used WCF clients from Windows Phone, Silverlight or Xamarin.iOS, you might have noticed that it is not possible to create Synchronous or Task-Based operations; the functionality is reduced to the Event-based Asynchronous Pattern (EAP). That means that the way to call a WCF method and get the response is usually as follows:

var client = new MyWCFClient();
client.DownloadDataCompleted += (sender, e) =>
{
 try
 {     
     //accessing e.Result here might raise an exception in another
     //thread, that will not be captured by the 'catch' below.
 }
 catch(Exception ex)
 {
 }
};
client.DownloadDataAsync(url);


Our results are wrapped in an auto-generated class that inherits from AsyncCompletedEventArgs, this class has a property Error of type Exception, that will carry information about the error and a property Result with our expected return value.

Accessing the property Result after a failed operation call, might cause cause an exception like this one: "An exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.ni.dll but was not handled in user code", you will also realize there is no place in your code that you could place a try-catch to capture it, and your application crashes...


The cause of the problem

The behavior is partially "by design". A quick look at the client  generated  code and you will find the root of the problem. The implementation of DownloadDataCompletedEventArgs contains this code:

 public MyTest.WrappedResultOfstring Result {
            get {
                base.RaiseExceptionIfNecessary();
                return ((MyTest.WrappedResultOfstring)(this.results[0]));
            }
        }
So they actually planned to throw an exception if there is something wrong with the operation, which is a good approach actually. However the exception is raised  in another thread.

The solution 

You must first check if the operation failed, and if it did, don't read the property Result, if you do it, then the exception will rise in another thread and it won't be possible to catch it, causing your application to fail. And in the case of Windows Phone and the other mobile apps, that means getting your app rejected from the store. Here is how you should always handle responses from WCF clients.

client.DownloadDataCompleted += (sender, e) =>
{
    if (e.Error != null)
            {
                //...
                //handle the error
                //but never even read from e.Result
            }
            else
            {
                // do something with e.Result
            }
};
 

Why the exception is raised in another thread is beyond me, however the solution to prevent it just implies a bit of good programming practices and nothing more.

Comments

Popular posts from this blog

Get-ChildItem vs Dir in PowerShell

The case for a 4 week sprint

NODE.js fs.readFile and the BOM marker