Exception Shielding #4: Customers Service Design
Now it's time to explain how the CustomersService service is designed and how this sample service implements Exception Shielding.
Architecture
As I stated before, the service uses the general architecture purposed by the Web Service Software Factory. The pieces look like this:
I wont get into the details of this architecture since it strictly follows the guidelines of the WSSF. You can read it here.
Instead, I highlighted in the picture the most important components to implement exception shielding:
- ICustomersService: this interface defines the service contract. Here you define the operations available and (important) the faults that each operation can return to the client.
- CustomersServiceFault: this class defines the generic fault contract used to return errors to the client (see previous post).
- CustomersServiceAdapter: this class is the actual implementation of the service operations. For the "create customer scenario" it instantiates a new CreateCustomer business action to service the request. This is the component that will actually implement the exception shielding mechanism.
Handling Exceptions
As I described earlier, we want to handle 2 different exceptions:
- When the client tries to create a customer that already exists. This exception is raised by the database and ultimately handled by the CustomerRepository data access component.
- When the client tries to create a customer without providing the minimum required data. This exception is raised by the CreateCustomer business action.
All other possible exceptions should be "mapped" to a generic service error.
To implement such behavior all the following three components should by designed with exception handling in mind:
- CustomerRepository:
- Catches the SqlException corresponding to the duplicate key insert error and throws a CustomerRepositoryException.
- CreateCustomer:
- Validates the customer's data contract received and raises a CreateCustomerException if it doesn't include all the required data.
- Catches CustomerRepositoryException and throws a corresponding CreateCustomerException.
- CustomersServiceAdapter:
- Catches CreateCustomerException and returns a CustomersServiceFault to the client.
- Catches all other kinds of exceptions and returns a CustomersServiceFault with a generic service error message.
Logging
The great benefit of the Exception Shielding design pattern is that you can use it to centralize the implementation of exception logging features. These features are essential for troubleshooting purposes, to allow the service administrator to know what's going on.
In an application like this one, exceptions can occur at two entirely different levels:
- On the client machine: for example, if the client is not capable of reaching the service.
- On the application server machine (the service host): according to the scenario described above.
I will not focus too much on the client side logging but I think it's important to understand how different that exception logging works comparing to the service side.
We will use the Enterprise Library Logging Application Block to implement the exception logging infrastructure. This infrastructure follows a very simple design (click image to enlarge):
The exceptions raised in the client layer will be logged to the Windows Event Log.
Considering that our service will ultimately be hosted in IIS - it will run (by default) under the Network Service account permissions - its exceptions will be logged to a simple flat file.
The good thing is that, since we will be using the Enterprise Library, this is completely configurable by the end-user after deployment, changing configuration in the app.config (client) and web.config (service) files.
And that's it for design. All we have left to do is to actually implement it.
Next time: Exception Shielding Implementation