Exception Shielding #3: Exception Shielding in WCF

The Windows Communication Foundation comes with a form of Exception Shielding out of the box.

As we'll see when we get to the implementation of the pattern in our CustomersService example, this has important implications on the service's design.

Fault Contracts

In WCF, unknown exceptions are not returned back to the client application to prevent details of the service implementation from leaving the boundary of the service. This is consistent with the first one of the 4 tenets of SOA: "boundaries are explicit".

In fact, for debugging purposes, this behavior can be modified by changing the includeExceptionDetailsInFaults property in the web.config file. Nevertheless this property if set to false by default and should remain that way in production environments.

So, by default, if any unhandled exception occurs in a service while executing any of its operations, WCF will return a generic fault with a (very) generic error message. My experience tells me that this message will vary depending on the service configuration and on the kind of error raised. But it will always be very generic and completely implementation details free. Normally, something like this:

The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.

This behavior, by design, relies solely on the concept of SOAP Faults to exchange error information between the client and the service.

The service will have to define custom fault content (known as Fault Contracts in WCF) and specify which of its operations can return them.

This is done by declaring a fault contract, which in turn is just a "special" kind of data contract, and applying the FaultContract attribute to the operations that are allowed to return that fault.

Consider the following example that I will explain further when I get to the implementation Exception Shielding in our CustomersService:

The fault contract is defined as follows:

using System;
using System.Runtime.Serialization;

namespace ServiceSoftware.CustomersService.FaultContracts
{
    [DataContract]
    public class CustomersServiceFault : DefaultFaultContract
    {
    }
}

That fault is "associated" with the operation using the FaultContract attribute:

using System;
using System.ServiceModel;
using ServiceSoftware.CustomersService.DataContracts;
using ServiceSoftware.CustomersService.FaultContracts;

namespace ServiceSoftware.CustomersService.ServiceContracts
{
    [ServiceContract(Name = "ICustomersService")]
    public interface ICustomersService
    {
        [OperationContract]
        [FaultContract(typeof(CustomersServiceFault))]
        void Create(Customer request);
    }
}

Exceptions and Fault Contracts

This design states only that the Create operation can return CustomersServiceFault faults to the client.

It's up to the service implementation to convey the correct fault in response to the correct exception. Once again, WCF helps by providing the System.ServiceModel.FaultException exception that allows the service to return a specific (and permitted) fault to the client. The following code shows an example of how this can be achieved:

using System;
using System.ServiceModel;
using ServiceSoftware.CustomersService.BusinessLogic;
using ServiceSoftware.CustomersService.ServiceContracts;
using ServiceSoftware.CustomersService.DataContracts;
using ServiceSoftware.CustomersService.FaultContracts;

namespace ServiceSoftware.CustomersService.ServiceImplementation
{
   public class CustomersServiceAdapter : ICustomersService
   {
      #region ICustomersService Members

      public void Create(Customer request)
      {

         try
         {

             // Perform service operations 

         }
         catch (Exception)
         {
             CustomersServiceFault fault =
                    new CustomersServiceFault();
             fault.ErrorId = -3000;
             fault.ErrorMessage = "An unexpected error " +
                    "has occurred while servicing your " +
                    "request."
             throw new FaultException<CustomersServiceFault>
                   
(fault);
         }

      }

      #endregion
   }
}

The previous code is basically swallowing any exception and returning a known fault that provides the client with a also generic exception. This is where we will implement our other 2 expected exceptions (see previous post) based on the type of exception raised. But we will come to that.

The points to retain here are the following:

  • By default, WCF does not allow the service to return any exception details to the client. Instead it returns a generic fault message.
  • Error conditions, in WCF, are returned to the client as SOAP faults.
  • These faults are defined as fault contracts (a kind of data contract) and you need to mark each operation that is allowed to return specific faults with the FaultContract attribute.
  • Faults are raised in the service implementation through the FaultException, passing the desired fault as parameter.

Next time: Customers Service Design

Published 28 April 07 01:28 by hgr
Filed under: , , ,

Comments

No Comments
Anonymous comments are disabled