WCF Exceptions in Silverlight

by mgordon 6. May 2009 08:49

I’ve been working on a fairly substantial Silverlight 2 application and finally took on an aspect of it that I had been dreading and putting off for some time – exception handling – specifically handling exceptions being thrown from my WCF services.  I just knew this was going to be a bear.  Turns out, it wasn’t quite as bad as I had feared, but it was enough trouble that I thought a blog post sharing the experience would be a good thing.

The Problem

Silverlight doesn’t communicate directly with your web services, but rather it uses the browser API for this communication.  When calling a web service, if any exception occurs, the browser converts this into a generic 400 (Page not found) error and hands it back to Silverlight.  The result is that inside your Silverlight application, you know that an exception has occurred during your call, but have no way of knowing what it was.  This problem is supposed to be fixed in version 3.

The Research

This was certainly something I didn’t want to rush into solving so I did a bit of research on the Internet before jumping in.  Some we solving this by using out parameters on their services that contained the exception information which required checking the value of this parameter after each call.  I found a solution that was quite nice on CodeProject that used attributes on the service methods and contracts and a base class for the proxy on the client.  Since I’m still using Visual Studio generated proxies in my project, this one aspect of the solution made it unusable for my purposes.  In a discussion, here, I discovered that Microsoft’s Silverlight web service team had published a solution to the problem.  I checked it out and decided on this solution for my application.  A blog post about the solution can be found here and the code can be downloaded from code.msdn.microsoft.com.

The Code and Configuration

I found a few blog posts from folks who had implemented this solution, but none that were comprehensive and none that addressed its use with Visual Studio generated proxies.  Below, then, are the steps I took to get it all working in my application.

First, download the code the Silverlight web service team makes available and compile all the solutions.  You’ll need to set references to a few of the generated assemblies.

References

In the web project containing your WCF web services, set a reference to the assembly “SilverlightFaultBehavior.dll”.  Now, in your Silverlight project set references to the assemblies “SilverlightRawFaults.dll” and “SilverlightMessageInspector.dll”.

Code

If the web project containing your WCF web services doesn’t have a Global.asax file, add it and add the following code to it.  This code will cause any service requests that fail to return a 200 status code instead of 400.

 

protected void Application_EndRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.PhysicalPath.EndsWith(".svc", StringComparison.OrdinalIgnoreCase) &&
        HttpContext.Current.Response.StatusCode == 500 &&
        !HttpContext.Current.Request.Browser.Crawler &&
        HttpContext.Current.Request.Browser.EcmaScriptVersion.Major > 0)
    {
        // Set 200 if its a faulted service request
        HttpContext.Current.Response.StatusCode = 200;
    }
}
 

In any Silverlight class that makes a call to a WCF service, add the following (C#).

using Microsoft.Silverlight.Samples;
using SilverlightRawFaults;

At the point where you’re making the WCF call, you’ll be creating an instance of the proxy for that service.  Before making the call on that proxy, replace its binding by adding a line similar to this.

proxy.Endpoint.Binding = new BasicHttpMessageInspectorBinding(new SilverlightFaultMessageInspector());

This binding will ensure that the message inspector has a chance to look at the message returned from your call.

Finally, in the completed event for your service call, you’ll need to evaluate the Error property on the passed in event argument. 

if (e.Error != null && e.Error is RawFaultException)
{
    RawFaultException exception = (RawFaultException)e.Error;
    MessageBox.Show("Service says: " + exception.FaultMessage + Environment.NewLine +
        "Exception type: " + exception.FaultType + Environment.NewLine +
        "Stack trace: " + exception.StackTrace);
}
The Bug

After making the above modifications to my code, the value of the FaultMessage was not what I was expecting.  No matter what the exception was, this property always had the same generic value.  I found that there was a bug in the code provided by the Silverlight web service team and once it was corrected, all worked as expected.

Correcting the Bug

To correct the bug, open the downloaded solution called “SilverlightRawFaults”.  In the SilverlightRawFaults project, you’ll find a class called “BasicHttpMessageInspectorBinding”.  There is a property on this class called “FaultMessage” (oddly enough, the value that was incorrect).  Change this

public string FaultMessage 
{
    get { return Message; } 
}

to this

public string FaultMessage 
{
    get { return message; } 
}

Note that all I changed was the case of the “M” in “message”.  In this class, message is a member variable where Message is a property of the base class which is never set.  In the method RawFaultException sets message to the string containing the exception’s message, which is the value that should be returned.

Tags:

.Net | Silverlight | WCF

Comments

7/31/2009 3:32:47 PM #

More about Silverlight RawFaults

More about Silverlight RawFaults

Enterprise Etc

Comments are closed

Powered by BlogEngine.NET 1.5.0.7
Theme by Extensive SEO