I have a asp.NET web service (not WCF but the classic .asmx one with WebMethods) that throws exceptions. The exceptions all derive from one of two base exception classes (both of which derive from Exception):
public class InputException : Exception
{
....
}
public class FatalException : Exception
{
....
}
public class NoFilesFound: FatalException
{
....
}
....
The webservice right now throws the exception as needed. In my client code I can catch the exceptions and see the message like this:
Server was unable to process request. ---> There were no files found
However the exception is of type FaultException (as seen when I do .GetType() on the caught exception). The calling client needs to be able to differentiate between an InputException and a FatalException (and optimally differentiate between the individual derived ones but that's not as important). Right now the only way to do so is to parse the message, strip the text before "--->" and switch on the text. That is clearly not optimal.
I know I can throw SoapExceptions with custom Code but I want to avoid that if possible. Furthermore it seems designed for those who deal with XML but all of our webservice code doesn't touch XML as it's deserialized for us already.
So in short, is there a way for me to throw custom exceptions from the webservice and for the calling client to be able to differentiate between the exceptions?
The proper way to handle this is to use a SoapException. So you will basically catch all possible exceptions on the service and then translate them to a SoapException (the documentation I have linked to contains an example) and then instead of throwing some custom exception of yours throw this SoapException and include the information you are interested in the Detail XML node of the fault.
Then when invoking the service on the client you will be able to catch this SoapException and analyze the Detail XML node to gather more details about the exact reason of the fault that occurred on the server.
All this manual generation of fault nodes has been rendered very easy in WCF where you simply work with data contracts and catch FaultException<SomeFaultContract>
.
Let's take an example. Suppose you have the following service method which throws a SoapException and provides details about the error in the Details node:
[WebMethod]
public string HelloWorld()
{
var doc = new XmlDocument();
var node = doc.CreateNode(
XmlNodeType.Element,
SoapException.DetailElementName.Name,
SoapException.DetailElementName.Namespace
);
// you could actually use any sub nodes here
// and pass even complex objects
node.InnerText = "no files found";
throw new SoapException(
"Fault occurred",
SoapException.ClientFaultCode,
Context.Request.Url.AbsoluteUri,
node
);
}
when consuming it you could catch for this SoapException on the client:
using (var client = new WebService1())
{
try
{
var result = client.HelloWorld();
}
catch (SoapException ex)
{
var detail = ex.Detail;
// detail.InnerText will contain the detail message
// as detail is an XmlNode if on the server you have
// provided a complex XML you would be able to fetch it here
}
}
As far as your InputException
, FatalException
and NoFilesFound
exceptions are concerned, they are fine, but they should stay on the server. Catch them in your web method and build a proper SoapException
that the client will be able to make sense of when consuming the service.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With