Search code examples
wcfsilverlightwcf-ria-servicessilverlight-5.0

How to properly handle WCF faults with Silverlight?


No matter how hard I try I cannot seem to be able to handle WCF faults in Silverlight. In fact the error seems to never leave the server !

E.g. when I debug it, it stops on the line where I throw the FaultException saying it was not handled:

[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class StoreService : IStoreContract
{
    public System.Collections.Generic.List<string> GetStoreDesignNames()
    {
        try
        {
            StoreDataContext swdc = new StoreDataContext();
            var query = from storeDesign in swdc.StoreDesignDBs select storeDesign.Name;
            return query.ToList();
        }
        catch (System.Data.SqlClient.SqlException sqlExcept)
        {
            throw new FaultException<SqlFault>(new SqlFault() { Message = sqlExcept.Message });
        }
    }
}

The class that implements this method derives from a contract interface:

[ServiceContract(Namespace = "Store")]
public interface IStoreContract
{
    /// <summary>
    /// Obtain the list of store design names.
    /// </summary>
    [OperationContract,
     FaultContract(typeof(SqlFault))]
    List<String> GetStoreDesignNames();
}

And the SqlFault class is defined like this:

public class SqlFault
{
    public String Message { get; set; }
}

On the client side I handle the error as follow:

        // swc is the client
        swc.GetStoreDesignNamesCompleted += new EventHandler<ServiceReference.GetStoreDesignNamesCompletedEventArgs>((obj, evt) =>
        {
            if (evt.Error == null)
            {
                // In case of success
                MessageBox.Show(evt.Result.First());
            }
            else if (evt.Error is FaultException<ServiceReference.SqlFault>)
            {
                FaultException<ServiceReference.SqlFault> fault = evt.Error as FaultException<ServiceReference.SqlFault>;
                Dispatcher.BeginInvoke(() =>
                {
                    ErrorWindow ew = new ErrorWindow(fault.Detail.Message, "No details");
                    ew.Show();
                });
            }
        });
        swc.GetStoreDesignNamesAsync();

I have tried to put the [SilverlightFaultBehavior] attribute on the interface, to no avail. Even if I do without the interface I still have this error.

I have also tried to use a behavior extension in the web.config as described here but I get a warning saying the extension is not valid.

How does one go about properly handling WCF fault in Siverlight ? Thanks in advance.


Solution

  • After battling with this for hours I finally hacked something together that works. This is really a horrible hack and I would have much preferred to use BehaviorExtension for this task. The trick is to set manually the HTTP status code in the body of the WCF method like so:

        public System.Collections.Generic.List<string> GetStoreDesignNames()
        {
            try
            {
                StoreDataContext swdc = new StoreDataContext();
                var query = from storeDesign in swdc.StoreDesignDBs select storeDesign.Name;
                return query.ToList();
            }
            catch (System.Data.SqlClient.SqlException sqlExcept)
            {
                System.ServiceModel.Web.WebOperationContext ctx = System.ServiceModel.Web.WebOperationContext.Current;
                ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
                throw new FaultException<SqlFault>(new SqlFault() { Message = sqlExcept.Message });
            }
        }
    

    The error message then correctly displays on the client side. If anybody has a better solution than this I'd like to hear it.