While writing the Silverlight applications at FunkyTools.com, I quickly found that not being able return exceptions from my WCF calls was a huge problem for me. I located a solution that had been released by the Silverlight WCF team and, at the time, learned just enough about the code to get it integrated into my solution. I documented how to use the code in a previous blog post. Recently, however, I’ve taken the time to dig into the code and learn more about how it works.
Why Faults Don’t Get Returned To Silverlight In The First Place
When Silverlight makes a WCF call, the communication with the server does not happen from the Silverlight application. Rather, Silverlight uses the browser API to originate the call and the response comes back to the browser, first, and it passes it back to our application. When an exception occurs in the WCF service, the return HTTP Response Code is changed from 200 to some other value to indicate the call was problematic. If a response code other than 200 is returned to the browser, Silverlight gets handed back a “Not Found”" Exception from the browser and the actual exception information is lost.
The Sample Solution
The sample solution contains 4 projects.
- SilverlightFaultBehavior – Defines a behavior that is added to a customer binding we can use to enable to have out exceptions returned.
- SilverlightMessageInspector – Defines a new Channel and Binding for use in the solution. This Project wires up the Channel, Binding, and behavior. These first two projects define all that’s needed to set up the server side of the functionality we desire.
- SilverlightRawFaults – Defines a single class that is of interest which is a message inspector – more on this in a second.
- SilverlightRawFaults.Web – A test web site to host the sample service.
This project defines a single class, SilverlightFaultBehavior, which extends BehaviorExtensionElement and IEndPointBehavior. Basically, it adds an additional behavior that we can tie to our bindings. In this class, there is a method IDispatchMessageInspector.BeforeSendReply that contains the following code:
HttpResponseMessageProperty property = new HttpResponseMessageProperty();
property.StatusCode = System.Net.HttpStatusCode.OK; // 200
reply.Properties[HttpResponseMessageProperty.Name] = property;
So, basically, just before the response is returned to the browser, this behavior sets the return code to 200 if it’s any other value.
This project is basically a plumbing project. It composes the behavior, channel and the message inspector into a binding, which when used, is pre-configured to return the exceptions we desire.
This project contains file SilverlightFaultRawMessageInspector.cs and defines the two classes needed on the client side. The file contains two classes; RawFaultException, a custom CommunicationException and SilverlightFaultMessageInspector which implements IClientMessageInspector. In the latter of these classes a method, AfterReceiveReply, contains this code:
if (reply != null && reply.Version == MessageVersion.Soap11)
throw new RawFaultException(reply.GetReaderAtBodyContents());
So, when the reply is received by Silverlight, but before it is returned to our application, this method checks to see if the reposonse contains a Soap 1.1 Fault and if it does, and instance of the custom CommunicationException is created that contains the fault details (error code, message and stack trace) and that exception instance is thrown into our application.
So, our response is inspected on the server and its response code is set back to 200 so the browser will interrupt the flow of our fault. Once Silverlight gets the response, our client side message inspector checks to see if a fault is contained in the response and if so, the fault is converted into an exception and thrown back to the method in our application that originated the call.