Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

SoapException.Message on the Client


:P
On this page:

I hate the way SoapExceptions return messages to the client. So, assume you have a server side WebMethod that throws a SoapException like this:

 

[WebMethod(Description="Returns messages using XML entity body content")]

public XmlNode GetMessagesXml(string Password)

{

 string PartnerId = this.GetPartnerIdFromPath();

 

 if (string.IsNullOrEmpty(PartnerId))

     throw new SoapException("Invalid Partner Id", SoapException.ServerFaultCode);

 

 // *** Validate user first

 busOmnicellUser User = new busOmnicellUser();

 if (!User.ValidateUser(PartnerId, Password))

     throw new SoapException(User.ErrorMessage,SoapException.ServerFaultCode);

}

 

The idea is to throw a SoapException from the service that means something back on the client. This code picks it up:

 

try

{

    node = Service.GetMessagesXml(this.Password);

}

catch (SoapException ex)

{

    this.SetError(Message);

    return null;

}

catch (Exception ex)

{

    this.SetError(ex.Message);

    return null;

}

 

If you look at a SoapException.Message you might get a mouthful like this:

 

System.Web.Services.Protocols.SoapException: Invalid PartnerId and Password\n   at Omnicell.OmnicellMessageService.GetMessagesXml(String Password) in c:\\Customers\\Omnicell\\OmniCellWeb\\App_Code\\OmnicellMessageService.cs:line 47

 

Ok, that it’s in verbose Debug mode. If you debug off in web.config the message gets a little cleaner:

 

System.Web.Services.Protocols.SoapException: Invalid PartnerId and Password\n   at Omnicell.OmnicellMessageService.GetMessagesXml(String Password)

 

Still a lot of information for an error message that includes a bunch of information that has no place in the message property of this exception. The detail of the message varies depending on whether the ASP.NET app is running in Debug mode (web.config setting). With debug on you’ll get the full call stack – but even without debug mode on you still get the exception name plus the name of the method on the server that fired the exception.

 

WTF? This sort of information is useful but it has no place in a MESSAGE property of an exception object. That’s what the stack trace – and if necessary the SoapException’s Detail property are for. Now the problem is on the server side which returns a SOAP Fault like this:

 

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <soap:Body>

        <soap:Fault>

            <faultcode>soap:Server</faultcode>

            <faultstring>

                System.Web.Services.Protocols.SoapException: Invalid PartnerId and Password

                at Omnicell.OmnicellMessageService.GetMessagesXml(String Password)

            </faultstring>

            <detail />

        </soap:Fault>

    </soap:Body>

</soap:Envelope>

 

Eh, why not break this message up and put the message into the faultstring and the extended info about where the error occurred and what’s going on in the detail? But no… Apparently you also can’t muck around with the SoapException on the server, so it looks like we’re stuck with these non-parsable error messages that can’t be passed on to the UI without some modification.

 

As it goes this is easy to fix, but what could possibly be the reason that SoapException is passing down this raw XML value into the error message? SoapException knows that it’s dealing with a soap exception so why can’t this information be parsed a little better? After all the message detail in the SOAP message itself is fairly cleanly delineated.

 

To fix up the message it’s easy enough to strip out the Soap Exception with code like this:

 

catch (SoapException ex)

{

    string Message = wwUtils.ExtractString(ex.Message, "SoapException: ", "\n\");

    if (string.IsNullOrEmpty(Message))

        Message = ex.Message;

    this.SetError(Message);

    return null;

}

 

Or maybe more safely:

 

string Message = wwUtils.ExtractString(ex.Message, "SoapException: ", "  at");

 

but I hate throwing this kind of code into applications.

 

ExtractString is a small helper function that, well, extracts a string from a set of delimiters. It’s useful for a lot of things like this…

 

It just seems to me like this was working differently in 1.1 where turning debug mode off ended up returning just the exception detail. I may be dreaming though <g> - because I can’t find a blog entry I thought I made about this a long time ago.

 


The Voices of Reason


 

Haacked
August 11, 2006

# re: SoapException.Message on the Client

Or you could decorate your method with my SerializedExceptionExtension so you don't have to try/catch in every web method.

This is a soap extension that allows you to send the original exception (if you so desire) to the client OR to just send pertinent information (for external non-trusted clients for example).

http://haacked.com/archive/2005/06/29/ExceptionInjectionUsingCustomSoapExtension.aspx

Rick Strahl
August 12, 2006

# re: SoapException.Message on the Client

Nice!!!

Anbu
September 28, 2006

# re: SoapException.Message on the Client

If the web service needs to talk to another web service to get the response, and the second service returns and HTTP Error code, how this code can be send to the client?

Is there a way to return the HTTP Status codes through SoapEnvelope or throwing an exception??

Ronen Festinger
July 01, 2012

# re: SoapException.Message on the Client


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2025