The other day I had to use a web service from a C# 2.0 application. No problem – the .NET 2.0-frameworks provides tons of functionality. To jump into the exciting issue, I’d generated the proxy classes using WSDL, and started communicating with the WS. When no errors occured everything worked fine, but if something went wrong I just got an standard non-informative SoapHeaderException with no details whatsoever. Certainly less useful than a wet newspaper.
The problem was that a SOAP-fault (this name avoids mixing up the concepts of SOAP- and run-time exceptions) occurred, but the actual description of the error in the SOAP-response was not deserialized properly and was therefore not included in the run-time exception. The SOAP-response looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <soapenv:envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://tews6/wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:body> <soapenv:fault> <faultcode>soapenv:Client</faultcode> <faultstring>Error performing operation.</faultstring> <detail> <imsexception version="6.0"> <exception> <name>CheckForDuplicates</name> <code>500</code> <description><!--[CDATA[User id johndoe is a duplicate. ProcessStep::BLTHValidate TabName: ERRORLEVEL::Error]]--></description> </exception> </imsexception> </detail> </soapenv:fault> </soapenv:body> </soapenv:envelope> |
I read about this several places, and all these said that it was just the way .NET worked in that area. Sounds a bit odd, but nevertheless I instead started to figure out how to solve it.
The solution is actually quite simple, but it took some time to figure out how it should be done. It consists of three parts:
- A custom Exception so that it can be caught separately
- A SoapExtension that handled serialization and deserialization of the SOAP-messages and in that way were possible to intervene if a SOAP-fault occurred and throw the custom exception instead of a generic SoapException
- It’s worth noticing that I used the ProcessMessage-method and especially the SoapMessage stage BeforeDeserialize
- A SoapExtensionAttribute used to mark the web methods should use the SOAP-extension
It actually works very well! The only drawback is that every web method has to be marked with the attribute – but just another opportunity to celebrate sed!
