(X) Hide this
    • Login
    • Join
      • Say No Bots Generate New Image
        By clicking 'Register' you accept the terms of use .

Handling service exceptions within Silverlight applications

(12 votes)
Gill Cleeren
>
Gill Cleeren
Joined Apr 02, 2010
Articles:   63
Comments:   6
More Articles
6 comments   /   posted on Jul 18, 2011
Categories:   Data Access , Line-of-Business , General

Most LOB applications in Silverlight work with services to get data to the client. Commonly used technologies on the server-side include WCF, WCF RIA Services and REST Services. When all communication with the service goes well and no service exceptions occur, the Silverlight application has nothing to worry about: it will get its data to display to the user. But what happens when things go down the drain on the server? The database can be down, the load on the server might be too high or a third-party service that needs to be invoked can’t be connected to. We can handle this on the server-side but we should be able to let the end-user know what went wrong. Perhaps, since it’s only a temporary problem, we’d like him to try again in a few seconds.

For that reason, we need to be able to capture the faults on the client. Also, during development, it’s vital to work productively that we know what went wrong within our service. The problem is that Silverlight does not get access to this information, being a browser plugin. There are two solutions available to solve this problem. This article shows you how you can get access to this information and also explains which solution should be followed in what situation.

The source code for this article can be downloaded here.

The cause of the problem

If from Silverlight, we are accessing a service and something goes wrong within that service, we would expect to get access from Silverlight to the error returned by the service. This way, we would have enough information to make adjustments to the service code or would know if perhaps the service was not accessible. Sadly, this is not the case. Every time a service returns a status 500 (Internal Server Error), in Silverlight, we see a 404 (Not Found), as can be seen in the screenshot below.

clip_image001

Silverlight says that the service can’t be found, even though we know it is accessible.

The reason for this is a limitation of the browser stack: a browser can only return to a plugin (such as Silverlight) a status 200 and 404. That means that if the state is not 200, whatever the state returned, Silverlight will see a 404. Because of this, we have no access to the service error.

How to solve things

Not all hope is lost though, there’s a solution: we can on the server change the status of the response to 200, if something goes wrong. This response is then available to Silverlight (remember, SL can only access 200 and 404) and we can thus read out the fault information within the Silverlight application.

Implementing this change of status code can be done through a service-side behavior that inspects the SOAP message and converts the status to 200. Note that it’s advised to create a specific endpoint for this purpose with this behavior if your service is going to be accessed from other clients than Silverlight!

Two possible types of faults

With this behavior in place, we actually have 2 types of faults that can be returned from the service, so-called declared faults and undeclared faults.

Undeclared faults are advised to be used in development/debugging scenarios. In this case, all error information from the service is returned to the client. This means that for example a database error including table names might be returned to the client, which is not something you’d want to happen in a production application.

On the other hand, declared faults are faults declared within the service code through the use of a FaultException. We as service code authors can declare these and return in the client code, we can act upon receiving these Faults.

We’ll see how to use both types in the next paragraph.

Implementation on the service-side

With Silverlight 4, when we add a Silverlight-enabled WCF service, Silverlight adds a file called SilverlightFaultBehavior.cs to the project. The generated class inherits from Attribute. I prefer to use a different one, which inherits from BehaviorExtensionElement. The code for this file is similar; it’s shown below.

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;
using System.ServiceModel.Dispatcher;
using System.ServiceModel;
 
namespace ServiceExceptionDemo.Web
{
    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();
        }
    }
}

This class implements the IEndpointBehavior, it’s itself a behavior that through configuration can be added onto a service endpoint. It’s easy to see what this class does: in the BeforeSendReply method, we are checking if the reply contains a Fault and if so, we set the status code to OK (which is 200).

It’s possible to extract this class to a separate class library and reference that project from the service project.

Just putting the behavior in place doesn’t really do a lot! It needs to be used inside the configuration of the service. The code below shows the updated configuration code for the service project.

<system.serviceModel>
  <extensions>
    <behaviorExtensions>
      <add name="silverlightFaults"
           type="ServiceExceptionDemo.Web.SilverlightFaultBehavior, 


           ServiceExceptionDemo.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
/>
 
    </behaviorExtensions>
  </extensions>
  <behaviors>
    <endpointBehaviors>
      <behavior name="SilverlightFaultBehavior">
        <silverlightFaults/>
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior name="">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <bindings>
    <customBinding>
      <binding name="ServiceExceptionDemo.Web.ProductService.customBinding0">
        
        <httpTransport />
      </binding>
    </customBinding>
  </bindings>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      multipleSiteBindingsEnabled="true" />
  <services>
    <service  name="ServiceExceptionDemo.Web.ProductService">
      <endpoint address="" binding="customBinding" 
                behaviorConfiguration="SilverlightFaultBehavior" 
                bindingConfiguration="ServiceExceptionDemo.Web.ProductService.customBinding0"
          contract="ServiceExceptionDemo.Web.ProductService" />
      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    </service>
  </services>
</system.serviceModel>

Note in this code that we are adding a new BehaviorExtension named SilverlightFaults. This is then added as a new endpoint behavior through service configuration. I also set includeExceptionDetailInFaults to true. This allows me to get all information about the error: WCF will embed the entire exception string in the returned message. This is what’s referred to as an undeclared fault.

Let’s go to the service code. We can now implement the service, including code that returns a service fault. In the service code, a method called GetProducts is added, which is shown below.

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ProductService
{
    [OperationContract]
    [FaultContract(typeof(ProductFault))]
    public List<Product> GetProducts(string searchTerm)
    {
        List<Product> products = GetAllProducts();
 
        var results = from p in products
                      where p.ProductName.Contains(searchTerm)
                      select p;
 
        if (results.Count<Product>() == 0)
        {
            ProductFault fault = new ProductFault();
            fault.Message = "No products found.";
            fault.AdditionalInfo = "Perhaps try a different search term.";
            throw new FaultException<ProductFault>(fault, "No results");
        }
 
        return results.ToList();
    }
 
    private List<Product> GetAllProducts()
    {
        return new List<Product>()
        {
            new Product(){ProductName="Tea", Price=5, Description="A fine Brittish tea"},
            new Product(){ProductName="Coffee", Price=7, Description="A pack of coffee from Starbucks"},
            new Product(){ProductName="Peanut butter", Price=2, Description="Some great peanut butter"},
            new Product(){ProductName="Hot Cocoa", Price=10, Description="Great for wintery days"},
        };
    }
}
 

There are several interesting aspects to this code. First, the method is attributed with the FaultContract(typeof(ProductFault)) attribute. This is basically saying that this service method may return a fault of this particular type. Because we are including this attribute here, in the proxy generation, this fault type will be included.

Here, when the user is searching, an error will be returned when no result can be found. We throw therefore a FaultException. With no fault behavior configured, this would result in a 404 within Silverlight. Now however, because of the configured behavior, every response will pass through the code and the response status code will be changed to 200.

The fault is of type ProductFault, which is shown next.

public class ProductFault    
{        
    public string Message { get; set; }        
    public string AdditionalInfo { get; set; }    
}

Using predefined faults and defining which information is included is known as using declared faults. As mentioned, this is the way to go in production environments.

Let’s now look at how we can effectively use this on the client. After adding a service reference in the Silverlight code, we are invoking the service as follows:

private void SearchButton_Click(object sender, RoutedEventArgs e)
{
    ProductService.ProductServiceClient proxy = new ProductService.ProductServiceClient();
    proxy.GetProductsCompleted += 
        new EventHandler<ProductService.GetProductsCompletedEventArgs>(proxy_GetProductsCompleted);
    proxy.GetProductsAsync(SearchTextBox.Text);
}
 
void proxy_GetProductsCompleted(object sender, ProductService.GetProductsCompletedEventArgs e)
{
    if (e.Error == null)
    {
        ProductsDataGrid.ItemsSource = e.Result;
    }
 
    else if (e.Error is FaultException<ProductFault>)
    {
        FaultException<ProductFault> serviceFault = e.Error as FaultException<ProductFault>;
        ErrorTextBlock.Text = serviceFault.Detail.Message + " " + serviceFault.Detail.AdditionalInfo;
    }
    else if (e.Error is FaultException<ExceptionDetail>)
    {
        FaultException<ExceptionDetail> serviceFault = e.Error as FaultException<ExceptionDetail>;
        ErrorTextBlock.Text = serviceFault.Detail.Message;
    }
}

In the callback, we are checking if an error was returned. If there is one, we can now check for a specific fault type (note that this way, we can have multiple types of faults being returned). Also, we have access to the information about the error after it came back from the service, which wasn’t possible before. The screenshot below shows what happens if we are searching for a product that doesn’t exist.

clip_image003

It’s very interesting to see that when stepping through the code, these exceptions can be seen as well. Here’s what happens in the service code (which we can always see):

clip_image004

However, inside the generated proxy code, we also see this information:

clip_image006

Also interesting to see is what happens if we take a look at the response using Fiddler. Because I set includeExceptionDetailInFaults to true, all error information is included, as can be seen below:

clip_image007

Summary

In this article, we looked at how we can through the use of a behavior have access to faults within Silverlight when talking to services. We saw there are two ways of doing this: using declared or undeclared faults.

About Gill

Gill Cleeren is Microsoft Regional Director (www.theregion.com), Silverlight MVP (former ASP.NET MVP), INETA speaker bureau member and Silverlight Insider. He lives in Belgium where he works as .NET architect at Ordina. Passionate about .NET, he’s always playing with the newest bits. In his role as Regional Director, Gill has given many sessions, webcasts and trainings on new as well as existing technologies, such as Silverlight, ASP.NET and WPF at conferences including TechEd Berlin 2010, TechDays Belgium, DevDays NL, NDC Oslo Norway, SQL Server Saturday Switserland, Spring Conference UK, Silverlight Roadshow in Sweden… He’s also the author of many articles in various developer magazines and for SilverlightShow.net. He organizes the yearly Community Day event in Belgium.

He also leads Visug (www.visug.be), the largest .NET user group in Belgium. Gill recently published his first book: “Silverlight 4 Data and Services Cookbook” (Packt Publishing). You can find his blog at www.snowball.be.

Twitter: @gillcleeren


Subscribe

Comments

  • Arterius

    Re: Handling service exceptions within Silverlight applications


    posted by Arterius on Jul 26, 2011 15:31

    I don't know but some think wrong in this article, maybe its not cover much area I would?

  • sharmadk3018

    Re: Handling service exceptions within Silverlight applications


    posted by sharmadk3018 on Aug 27, 2011 11:20

    Hi,

    in my demo solution its working fine..but when i try to implement the same in my actual solution its giving me an error on

    Line 17:       <endpointBehaviors>
    Line 18:         <behavior name="SilverlightFaultBehavior">
    Line 19:           <silverlightFaults/>
    Line 20:         </behavior>
    Line 21:       </endpointBehaviors>

    ERRROR --

    Configuration Error

    Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

    Parser Error Message: The type 'TachowebServices.SilverlightFaultBehavior,TachowebServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' registered for extension 'silverlightFaults' could not be loaded.

    PLEse Help me out .

     

  • gillcleeren

    Re: Handling service exceptions within Silverlight applications


    posted by gillcleeren on Aug 27, 2011 21:57
    Did you reference the project containing the behavior class?
  • jtowell

    Re: Handling service exceptions within Silverlight applications


    posted by jtowell on Sep 07, 2011 14:52
    Can this technique be retrofitted to a solution created from "Silverlight Business Application" template, which uses Ria Services?  Currently, this template has allowed me to create a complex solution without having to know anything about endPoints.

    James

  • zak248

    Re: Handling service exceptions within Silverlight applications


    posted by zak248 on Jan 11, 2013 10:13

    Hi,

    I want to use this with basicHttpBinding with windows authentication, I tried but its not working.

  • zak248

    Re: Handling service exceptions within Silverlight applications


    posted by zak248 on Jan 11, 2013 11:55

    Hi,

    I want to use this with basicHttpBinding with windows authentication, I tried but its not working.

Add Comment

Login to comment:
  *      *