Share via


Creating and Handling Faults in Silverlight

Silverlight version 3 enables support for the Windows Communication Foundation (WCF) SOAP fault programming model, which allows the service to communicate error conditions to the client. In previous versions of Silverlight, if an error occurred on the service, it would register as an HTTP 500 response code and details about the error would not be accessible to the Silverlight client.

Exceptions on the service are converted into SOAP faults before being sent by the service, and then they are converted from SOAP faults back into fault exceptions after they are received by the Silverlight client. The fault message contains a standard set of properties and an extensible detail object, whose content is controlled by the service. Depending on the contents of the detail object, a fault can be either defined or undefined.

  • Undeclared faults are useful when debugging a service. The fault message can contain relevant information about the server exception, such as the exception type, the message, and a stack trace.

  • Declared faults are useful in production environments when the client logic needs to be driven by the error condition. The service developer defines a fault type, which is included in the fault message and controls exactly what information the fault type carries on the wire.

The fault type is exposed in the service metadata, so Silverlight clients can have a strongly typed experience when working with the fault type and build their logic around it.

For more information about the handling of SOAP faults in WCF, see Specifying and Handling Faults in Contracts and Services.

Configuring WCF Faults for Use with Silverlight Clients

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 send faults to a Silverlight client that are accessible to it, an WCF service must modify the way it sends its fault messages. The key change needed is for WCF to return fault messages 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.

The modification on the server can be made by defining a WCF endpoint behavior for Silverlight faults. The following code sample shows how to do this.

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

    }

The code for this WCF endpoint behavior needs to be configured for the service in the WCF service configuration file. The modification needed is shown in the following code sample. Note that some sections have been omitted for clarity.

<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name=”silverlightFaults” 
             type=”Microsoft.Silverlight.Samples.SilverlightFaultBehavior, 
             SilverlightFaultBehavior, 
             Version=1.0.0.0, 
             Culture=neutral, 
             PublicKeyToken=null”/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
        <endpointBehaviors>
          <behavior name=”SilverlightFaultBehavior”>
            <silverlightFaults/>
          </behavior>
        </endpointBehaviors>
    </behaviors>
    <services>
        <service name=”Calculator.Web.Service”>
            <endpoint address=”” 
                      binding=”basicHttpBinding” 
                      contract=”Calculator.Web.Service” 
                      behaviorConfiguration=”SilverlightFaultBehavior” />
</service>
  </services>
</system.serviceModel> 

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

Using Undeclared 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 and are discussed in the next section. Undeclared SOAP faults are not specified in the contract for an operation. These SOAP faults are used only for debugging and are discussed in this section.

Undeclared SOAP faults are useful for debugging a service. It is simple to enable these undefined faults to propagate 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"/>

In the Silverlight client code, the fault can be handled inside the Web service operation response callback.

void proxy_CalculateCompleted(object sender, CalculateCompletedEventArgs e)
{
    if (e.Error == null)
    {
        // In case of success
    }
    else if (e.Error is FaultException<ExceptionDetail>)
    {
        FaultException<ExceptionDetail> fault = e.Error as FaultException<ExceptionDetail>;

         // fault.Detail.Type contains the server exception type.
         // fault.Detail.Message contains the server exception message.
         // fault.Detail.StackTrace contains the server stack trace.
         
    }
}

Note

This WCF configuration should never be deployed in production environments, because it exposes sensitive server-side data such as the exception type and stack trace, which presents a security risk.

Using Defined Faults to Drive Logic

To use faults in production, you define a fault type in the WCF service, which can contain only information that is safe to expose publicly. For example, a math service could define the following fault type.

public enum Operation
{
    Add,
    Subtract,
    Multiply,
    Divide
}

public class ArithmeticFault
{
    public Operation Operation { get; set; }
    public string Description { get; set; }
}

The operation in which a fault might occur must be marked with the System.ServiceModel.FaultContractAttribute attribute, so that WCF exposes the type in the service metadata.

[OperationContract]
[FaultContract(typeof(ArithmeticFault))]
public int Calculate(Operation op, int a, int b)
{
    // ...
}

The System.ServiceModel.FaultException<T> class is used to send the fault on the wire.

ArithmeticFault fault = new ArithmeticFault();
fault.Operation = Operation.Divide;
fault.Description = "Cannot divide by zero.";
throw new FaultException<ArithmeticFault>(fault);

When generating a proxy to this WCF service for Silverlight, Visual Studio 2008 will generate code for the ArithmeticFault class because it was exposed in the service metadata. This enables the class to be used inside of the Silverlight client to drive programming logic.

void proxy_CalculateCompleted(object sender, CalculateCompletedEventArgs e)
{
    if (e.Error == null)
    {
        // In case of success
    }
    else if (e.Error is FaultException<ArithmeticFault>)
    {
        FaultException<ArithmeticFault> fault = e.Error as FaultException<ArithmeticFault>;

        // fault.Detail.Operation as defined on the service
        // fault.Detail.Description as defined on the service

    }
}

See Also

Other Resources

Specifying and Handling Faults in Contracts and Services