Friday, September 14, 2007

ASP.Net Hack for Processing SOAP Faults on Clients that Hate the HTTP 500

Occasionally you may need to execute some SOAP operations using a client that doesn't understand SOAP. If this client doesn't like the HTTP 500 that comes back when the server generates a SOAP Fault (behavior specified in the SOAP spec), you may not be able to read the content that comes back, with the actual fault XML in it.

For example, I recently needed to use URLLoader and HTTPService to access a SOAP service in Flex, because the WebService (SOAP) implementation didn't like the server's WSDL. Admittedly, the WSDL included some legacy XML schema, and was a bit unusual, but it did validate. So it seems plausible that other valid services might also be inaccessible to the Flash/Flex WebService or other SOAP clients.

With HTTPService and ActionScript 3 E4X support, it's not terribly painful to do the SOAP client work yourself... until you get a SOAP Fault. The 500 causes HTTPService and URLLoader to abort and they do not return the document content to the application.

In this instance, I couldn't alter the web service itself, and didn't have the resources to build a new HTTP client on flash.net.Socket. That's the setup. Here's the hack, for IIS/ASP.net services:

Concept: alter the ASP.Net processing pipeline to return OK (HTTP 200) in place of a 500, but only when the SOAP fault is the cause of the 500. The way to do this is to use an ASP.Net facility called a Soap Extension to allow programmatic reading and/or writing to the SOAP message stream as it passes into and out of the application. Find the message in the state you don't like. Alter it. Done.

  1. Create a C# DLL project in Visual Studio and pull in boilerplate code for a System.Web.Services.Protocols.SoapExtension (MSDN docs and MSDN magazine have sample code, or look here)
  2. Pull out everything you don't need (which is most of it, if you're looking at a real-life sample)
  3. Locate the ProcessMessage method, and check for the SoapMessageStage.AfterSerialize lifecycle value. In most samples, there's a switch statement on the SoapMessageStage, so you can just identify the proper branch (the others should be blank for this basic solution)
  4. Add the following code:
       if (message.Exception != null)
          HttpContext.Current.Response.StatusCode = 200;
  5. Build. Place resultant DLL with other precompiled binaries used by the ASP.Net application.
  6. To tell ASP.Net to use this extension, add the following XML tag to the application's web.config, and all SOAP calls will use your extension. Find (and/or create) the <soapExtensionTypes> tag (under <webservices>, under <system.web>), and add

  7. <add type="YourSoapExtNamespance.YourSoapExtClassName, YourSoapExtAssemblyName" priority="1"  group="High" /> 

That's it. One line of code, a little configuration, and your hack is on. For a little more context, I've put the full SoapExtension class here.

3 comments:

Shrike said...

Great solution (despite only for our IIS in control). This is what I really need. Thanks a million.

It would be great if we still can get what is returned from URLLoader when encoutering http 500.

JimmySu said...

Good!I have fixed this kind of issue according to this solution. Actually this issue happened in firefox browser when flex application request a asp.net web service that return a soap exception.

MapleStory Mesos said...

I just found the article and get already been reading material on. I would like to verbalize the appreciation of the authorship science and ability to defecate followers read right away to the conclusion. I'd prefer to read simple things more modern blogposts as well as part my feelings with you.
MapleStory Mesos
Runescape Gold