.NET Exceptions – System.Web.Services.Protocols.SoapException

Making our way through the detailed .NET Exception Handling series, today we’ll be tackling the System.Web.Services.Protocols.SoapException. The SoapException is only the second exception we’ve covered in this series that deals with the Windows Communication Foundation (WCF) framework, which is used to build service-oriented applications. The System.Web.Services.Protocols.SoapException is a rather fundamental error type, as it’s the basis of exceptions thrown by WCF apps when a client makes service calls via the SOAP protocol.

In this article we’ll explore the SoapException in more detail, looking at where it fits within the .NET exception hierarchy, along with some sample code to illustrate how SoapExceptions are best thrown (and caught) in your own apps. Let’s get to it!

The Technical Rundown

When Should You Use It?

The sample code we’ll be using has just one major goal: Produce an exception on the server side (within the service), which should translate into a SoapException on the client side. Since we’ll be dealing with the WCF framework and a service application to illustrate how System.Web.Services.Protocols.SoapExceptions should be used, we’ll be using some of the example service application code from our System.ServiceModel.FaultException article. We’ll begin with the full sample code example below, after which we’ll dig into it in a bit more detail.

Before we break down the example code, it’s worth noting that the type of application this code is used in matters (to some degree). In particular, since we’re using the WCF framework for the LibraryService.ILibraryService interface and the LibraryService.LibraryService class, that code should be used in a WCF Service Library or similar project. This will generate some proper defaults values within files like the critical App.config.

With that out of the way, let’s dig into the code. We begin with a basic Book class that implements the IBook interface, which we’ll use as the basis of our service:

Next comes the basic structure of our service. We’ve defined the InvalidBookFault class, which applies the DataContract attribute (along with the DataMember attribute for its properties). These attributes simply tell the runtime that this object can be serialized (i.e. transformed to and from text)making it easier to transfer across the web:

We then make use of that InvalidBookFault class in the ILibraryService interface, which declares just one ReserveBook method. The interface applies the ServiceContract attribute, which does what it sounds like and creates a service contract with the underlying WCF application. The ReserveBook method’s OperationContract is used in conjunction with ServiceContract, informing the service that this method can be invoked by the WCF app. Lastly, the FaultContract attribute specifies that we want any errors during processing within this method to return an InvalidBookFault (instead of the default FaultException):

The final part of our service code is the actual ReserveBook(string title, string author) method implementation. This method doesn’t do much and is mostly just an example, but its purpose is to reserve a book based on the passed title and author. If either field is empty an exception is thrown, otherwise the book is reserved and output is displayed:

Now that our service layer is all setup we can move onto the client code, which isn’t too fancy. It begins by creating a new client connection to the LibraryServiceReference, then tries to reserve two books (first a valid, then an invalid one that’s missing an author argument). It also has numerous catch clauses to handle any unexpected exceptions:

If we execute the above client code and attempt to reserve some books we get the following output including a success then a failure:

There’s a couple interesting things going on here. Consider that the LibraryService.ReserveBook(string title, string author) method explicitly throws a System.Web.Services.Protocols.SoapException when a reservation fails. Moreover, the ILibraryService interface implemented a FaultContract attribute, so we return a LibraryServiceReference.InvalidBookFault if something goes wrong. However, in spite of both of these, we can see from the above output that our client code ended up catching a plain FaultException.

As indicated by the error message, this is due to the configuration of the service application. Specifically, we currently have the <serviceDebug includeExceptionDetailInFaults="False" /> behavior set, which suppresses some exception details that would otherwise be included. Let’s try setting that value to True and rerunning our client code:

Even though we’re still catching a basic FaultException on the client side, we’re able to see that the underlying reason (the base exception on the server side) was a System.Web.Services.Protocols.SoapException, which was our intent. However, we’re still not making use of the custom InvalidBookFault that we created.

As it happens, the proper way to handle custom exceptions on the server side of a WCF service application is to explicitly create a new instance of the fault object when it’s necessary, then throw a FaultException<T> of that type. Therefore, we’ve surrounded our logical code within the LibraryService.ReserveBook(string title, string author) method with a try-catch block that catches a SoapException. When a SoapException is caught we create a new InvalidBookFault instance, assign some values to its properties, then throw a new FaultException<InvalidBookFault> and pass in the InvalidBookFault instance that was created:

As a result, calling the service from our client code now produces the following output:

We’re now able to catch all expected exceptions throughout the process, both server side and client side.

To get the most out of your own applications and to fully manage any and all .NET Exceptions, check out the Airbrake .NET Bug Handler, offering real-time alerts and instantaneous insight into what went wrong with your .NET code, along with built-in support for a variety of popular development integrations including: JIRA, GitHub, Bitbucket, and much more.