Silverlight 3 and WCF Faults

On  a previous project that utilised WCF and Silverlight 2, I began implementing an error handling strategy that was going to rely on certain FaultExceptions being propagated to the Silverlight client. Well it turned out that Silverlight 2 does not support FaultExceptions so that was not going to fly and a custom solution was built.

Well Silverlight 3 does change this to some degree. Silverlight 3 now supports to the notion of Fault Contracts and FaultExceptions. In your Silverlight client code, if I have a WCF service called ThrowExceptionMethod (which as you may have guessed throws a FaultException) you can do something like this:

First wire up the service call:

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    TestRef.TestServiceClient client = new TestSilverlightApplication3.TestRef.TestServiceClient();
    client.ThrowExceptionMethodCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_ThrowExceptionMethodCompleted);
    client.ThrowExceptionMethodAsync();
}

Then handle any error situation in the completed event:

void client_ThrowExceptionMethodCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
    if (e.Error == null)
        MessageBox.Show("Call sucessfull");
    else
    {
        string msg;
        FaultException<ExceptionDetail> fex = e.Error as FaultException<ExceptionDetail>;
        if (fex != null)
            msg = string.Format("Fault Exception recevied. Reason: {0}, Message: {1}", fex.Reason, e.Error.Message);
        else
            msg = string.Format("Error recevied of type: {0}, Message: {1}",e.Error.GetType(),e.Error.Message);
        MessageBox.Show(msg);
    }
}

Here you can see that we test the ‘e.Error’ property to see if its an exception of type FaultException, otherwise the error will flow through generally as a CommunicationException as per normal WCF behaviour.

That all sounds easy, however you still need to tell the WCF service (or more specifically WCF itself) to return the fault using a HTTP status code of 200 (OK) instead of a HTTP status code of 500 (server error) which is the default. If you don’t do this, then the error will always come through as a CommunicationException .

You need a little bit of code and configuration for this. First you need to define a custom behaviour like so:

public class SilverlightFaultBehavior : BehaviorExtensionElement, IEndpointBehavior
    {        
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            SilverlightFaultMessageInspector inspector = new SilverlightFaultMessageInspector();
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
        }

        public class SilverlightFaultMessageInspector : IDispatchMessageInspector
        {
            public void BeforeSendReply(ref Message reply, object correlationState)
            {
                if (reply.IsFault)
                {
                    HttpResponseMessageProperty property = new HttpResponseMessageProperty();

                    // Here the response code is changed to 200.
                    property.StatusCode = System.Net.HttpStatusCode.OK;
                    reply.Properties[HttpResponseMessageProperty.Name] = property;
                }
            }
            
            public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
            {
                // Do nothing to the incoming message.
                return null;
            }
        }

        // The following methods are stubs and not relevant. 
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }
        public void Validate(ServiceEndpoint endpoint)
        {
        }
        public override System.Type BehaviorType
        {
            get { return typeof(SilverlightFaultBehavior); }
        }
        protected override object CreateBehavior()
        {
            return new SilverlightFaultBehavior();
        }
    }

Then some config:

<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name=”silverlightFaults” 
             type=”Microsoft.Silverlight.Samples.SilverlightFaultBehavior, 
             SilverlightFaultBehavior, 
             Version=1.0.0.0, 
             Culture=neutral, 
             PublicKeyToken=null/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
        <endpointBehaviors>
          <behavior name=”SilverlightFaultBehavior”>
            <silverlightFaults/>
          </behavior>
        </endpointBehaviors>
    </behaviors>
    <services>
        <service name=”Calculator.Web.Service”>
            <endpoint address=”” 
                      binding=”basicHttpBinding” 
                      contract=”Calculator.Web.Service” 
                      behaviorConfiguration=”SilverlightFaultBehavior” />
</service>
  </services>
</system.serviceModel> 

So, its still not quite there yet, but its better. It would be nice if this status code behaviour were part of the default Silverlight service template and that it was a provided behaviour, rather than a roll your own custom one.

Note: The custom behaviour, as well as more information on this subject, can and was taken from this article here.

3 Comments

Comments have been disabled for this content.