Click here to Skip to main content
15,867,704 members
Articles / Desktop Programming / XAML

Retrieve WebService Exceptions from a Silverlight Client

Rate me:
Please Sign up or sign in to vote.
4.92/5 (10 votes)
23 Jan 2010Public Domain2 min read 37.9K   349   25   8
This article shows how to retrieve exceptions from a Web Service to a Silverlight Client by creating a WCF endpoint behavior.

Introduction

By default, exceptions thrown in a WCF service are not returned to the Silverlight client, and everybody knows exception handling is critical for any enterprise solution, i.e., to notify users that a fault happens or for debugging purposes.

Before writing this article, I searched a lot about how to retrieve exceptions from Web Services to a Silverlight client. Most articles talk about implementing a custom error object whose attributes are populated with the error exception in the Web Service and the object passed from the Web Service to the Silverlight client. Although this can be quite a good solution, this adds additional overhead in retrieving the exception message from client side. What we want here is to retrieve the error directly from the e event handler, such as below:

C#
private void customerService_Completed(object sender, 
             GenerateErrorCompletedEventArgs e)
{
   if (e.Error == null)
   {
     myOutput.Text = "Sucess";
   }
   else
   {
     myOutput.Text = e.Error.Message.ToString();
   }
}

Background

By default, WCF services return fault messages with an HTTP 500 response code. Due to limitations in the browser networking stack, the bodies of these messages are inaccessible within Silverlight, and consequently, the fault messages cannot be read by the client.

To override this constraint and to make Silverlight clients retrieve faults, the key is to make the WCF service return the fault message with an HTTP 200 response code instead of the HTTP 500 response code. This change enables Silverlight to read the body of the message, and also enables WCF clients of the same service to continue working using their normal fault-handling procedures; hence, no refactoring is needed for existing client codes.

Using the Code

The ServiceFaultBehavior class from ServiceFaultBehavior.cs in the attached source code implements the IEndpointBehavior interface used for writing custom endpoint behaviors. The main implementation is the ApplyDispatchBehavior method which applies the ServiceFaultMessageInspector to the WCF endpoint behavior.

C#
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

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

   // 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(ServiceFaultBehavior); }
   }

   protected override object CreateBehavior()
   {
      return new ServiceFaultBehavior();
   }
}
}

It is the ServiceFaultMessageInspector class which changes the HTTP response from HTTP 500 to HTTP 200, if the reply is a Fault, by using its BeforeSendReply method.

C#
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

namespace Service
{

/// <summary>
/// Change reponse code from HTTP 500 to HTTP 200 works with 
/// <see "Service.ServiceFaultBehavior" />
/// </summary>
public class ServiceFaultMessageInspector : 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;
     }
}
}

Configuration

Don't forget to configure the <system.serviceModel> section in the WCF Service web.config to apply the new WCF endpoint behavior to the service.

XML
<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="serviceFaults" 
        type="Service.ServiceFaultBehavior, 
        Service, 
        Version=1.0.0.0, 
        Culture=neutral, 
        PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ServiceFaultBehavior">
          <serviceFaults/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="Service.CustomerServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <services>
      <service behaviorConfiguration="Service.CustomerServiceBehavior" 
      name="Service.CustomerService">
        <endpoint address="" behaviorConfiguration="ServiceFaultBehavior" 
        binding="basicHttpBinding" contract="Service.CustomerService"/>
        <!--<endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange"/>-->
      </service>
    </services>
</system.serviceModel>

After this modification is made to the WCF service, faults will be accessible to Silverlight clients that access this service.

Retrieving Faults for Debugging

Two types of SOAP faults can be sent: Declared and Undeclared. Declared SOAP faults are those in which an operation has a FaultContractAttribute attribute that specifies a custom SOAP fault type. These SOAP faults are used in production. Undeclared SOAP faults are not specified in the contract for an operation. These SOAP faults are used only for debugging.

Undeclared SOAP faults are useful for debugging a service. It is simple to enable these undefined faults to propagate the complete information about an exception in the fault message sent from the service to the client. This is done by setting the includeExceptionDetailInFaults attribute of the <serviceDebug> configuration element to true.

XML
<serviceDebug includeExceptionDetailInFaults="true"/>

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Mauritius Mauritius
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralCan't get this to work Pin
NeCroFire9-Dec-10 0:43
NeCroFire9-Dec-10 0:43 
GeneralRe: Can't get this to work Pin
NeCroFire9-Dec-10 1:50
NeCroFire9-Dec-10 1:50 
Question[My vote of 1] you could not have copied it from msdn? Pin
josephpotgieter1-Jul-10 3:50
josephpotgieter1-Jul-10 3:50 
GeneralMy vote of 1 Pin
josephpotgieter30-Jun-10 4:56
josephpotgieter30-Jun-10 4:56 
this was copied from msdn
GeneralSince Silverlight 3, one can also use the Client HTTP Stack Pin
Michael Epner27-Jan-10 5:04
Michael Epner27-Jan-10 5:04 
QuestionHow do you know I was looking for such tips ? Pin
Crusty Applesniffer25-Jan-10 21:37
Crusty Applesniffer25-Jan-10 21:37 
GeneralImpressive; I give it a 5 Pin
accent12325-Jan-10 15:46
accent12325-Jan-10 15:46 
GeneralI like it, so made it public and gave it a 5 vote Pin
Sacha Barber23-Jan-10 21:12
Sacha Barber23-Jan-10 21:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.