1. Every web service method should catch System.Exception and wrap the exception in a SoapException, adding necessary details to the Detail property of the exception. Please note that the xml node provided to this property must have the root name "[Dd]etail". It is recommended that you create the root element utilizing the SoapException.DetailElementName.Name and SoapException.DetailElementName.Namespace constants.
2. You must also provide the detail node as a node from a document(such as myXmlDoc.DocumentElement) and cannot just pass the XmlDocument.
3. The InnerException property of your custom SoapException will always be ignored. This is used by the framework for unhandled exceptions of types other than SoapException.
4. To work with SoapException details, it makes sense to have a helper method to wrap other exceptions such that every catch block can simply throw via a call to the helper:
[WebMethod]
public string SomeMethod()
{
try
{
//do something
}
catch(System.Exception excep)
{
throw GetSoapException("Failed to do something",excep);
}
}
private SoapException GetSoapException(string message, System.Exception originalException)
{
StackTrace trace = new StackTrace(1);
SoapException eSoap = new SoapException(message,
SoapException.ServerFaultCode, //Could be ClientFaultCode depending on circumstances.
trace.GetFrame(0).GetMethod().Name,
detail.GetSerializedData(), //detail is some serializable object with xml nodes providing
//exception info. Cut from this sample for clarity.
excep);
return eSoap;
}
5. ServerFaultCode and ClientFaultCode are not necessarily important to set properly, but they indicate what the cause of the problem was. You should indicate a ServerFaultCode if something went wrong in the normal operation of the service. This might be the case if you are wrapping an exception from your catch block. If you intentionally throwing a fault because the client has sent bad data:
if(String.IsNullOrEmpty(someInputString))
throw GetSoapException("Your input string was null or empty",
new ArgumentNullException("someInputString"));
you would indicate this via the ClientFaultCode code.
6. If you want to have a serializable object which contains error details, you will need to expose this to the client code via customizations to your wsdl document. Alternatively, the client code could have its own version of the object via a seperate shared assembly. Whatever makes sense.
7. The client should then have a catch block for SoapException around all web service calls, and some helper method for deserializing the Detail property and taking action based on the contents.
Links :
Using SOAP Faults
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service09172002.asp
Handling and Throwing Exceptions in XML Web Services
http://msdn2.microsoft.com/en-us/library/ds492xtk.aspx
SoapException.Detail Property
http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.soapexception.detail(VS.80).aspx
Discussion on InnerException
http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.dotnet.framework.webservices&tid=48c5c279-1982-462d-8a2d-10db072671bb
2 comments:
I guess I don't understand where the information comes from to fill in "details".
In the example, the only parameters, is a brief description, and the exceptin itself.
I know you cut it out for clarity, but I need to see an example on how to initialize this node with good information.
Thanks
Hi Paul,
In the example I drew from code that used a class object like
class Details
{
public string message {get{;}set{;}};
public string stackTrace{get{;}set{;}};
}
where I put Xml Serialization attributes on the properties. You could get as fancy as you like with that.
You could also simply create a details element like this:
XmlDocument detailDoc = new XmlDocument();
detailDoc.LoadXml("<Detail><Some other xml in here/></Detail>");
SoapException eSoap = new SoapException("message",SoapException.ServerFaultCode, "FailedMethodName",detailDoc.DocumentElement,null);
Post a Comment