Click here to Skip to main content
11,580,000 members (73,518 online)
Click here to Skip to main content

Retrieve WebService Exceptions from a Silverlight Client

, 23 Jan 2010 Public Domain 20.1K 327 25
Rate this:
Please Sign up or sign in to vote.
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:

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.

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.

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.

<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.

<serviceDebug includeExceptionDetailInFaults="true"/>

License

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

Share

About the Author

ds47
Mauritius Mauritius
No Biography provided

You may also be interested in...

Comments and Discussions

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

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150603.1 | Last Updated 24 Jan 2010
Article Copyright 2010 by ds47
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid