Thursday 27 October 2011

Handling WCF faults in Silverlight

Here’s a quick reminder to self about handling SOAP faults in Silverlight applications, something that happened recently and I forgot a simple step.

Before going any further read this (it will probably answer all your questions): Creating and Handling Faults in Silverlight

Firstly, I had a WCF service that was exposing faults contracts using the [FaultContract] attribute.

[ServiceContract(Namespace = "http://some_namespace_here/ConfigurationService/2011/10/01/01", Name = "ConfigurationService")]
public interface IConfigurationService
{
    [OperationContract(Name = "GetConfiguration")]
    [FaultContract(typeof(MyFault))]
    [FaultContract(typeof(ValidationFault))]
    ConfigurationResponse GetConfiguration(ConfigurationRequest request);
}

The service was implemented along with fault types, for example:

[DataContract(Namespace = "http://some_namespace_here/WIRM/2011/10/01/01", Name = "MyFault")]
public class MyFault
{
    [DataMember(IsRequired = true, Name = "FaultDetail", Order = 0)]
    public string FaultDetail { get; set; }

    [DataMember(IsRequired = true, Name = "FaultCode", Order = 1)]
    public string FaultCode { get; set; }
}

The problem was that back in Silverlight when I was handling exceptions generated from service calls the exception didn’t have the specific detail of the fault. The trick to making this work is in the article linked to above. We chose to use the “alternative client HTTP stack” approach by adding this to App.xaml.cs:

public partial class App : Application
{
    public App()
    {
        bool registerResult = WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
        InitializeComponent();
    }
}

Thereafter it was possible to get at the actual fault exceptions and take advantage of specific exception details:

private void ClientGetConfigurationCompleted(object sender, GetGetConfigurationEventArgs e)
{
    if (e.Error == null)
    {
        // Do normal processing here...
        return;
    }
            
    if (e.Error is FaultException<ValidationFault>)
    {   
        var ex = e.Error as FaultException<ValidationFault>;
        // Do stuff with validation errors (via ex.Detail)
    }
            
    if (e.Error is FaultException<MyFault>)
    {
        var ex = e.Error as FaultException<WirmFault>;
        // Do stuff with MyFault (via ex.Detail)
    }
}

That’s it.