I'm fairly happy with my global unhandled exception handler for WinForms and console apps. I also successfully adapted a version of it for use in ASP.NET apps, where it interfaces with the Application_Error event in global.asax:
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Fires when an error occurs
Dim ueh As New AspUnhandledExceptionHandler(True)
ueh.HandleException(Server.GetLastError.GetBaseException())
End Sub
What I haven't been able to do, however, is get it to work with NET web services. Application_Error never fires for a web service. According to my research, there really is no good way to generically handle unhandled exception in .NET web services. All the alternatives are.. well, bad. Here's what you can do:
Private Sub WebServiceExceptionHandler(ByVal ex As Exception)
Dim ueh As New AspUnhandledExceptionHandler
ueh.HandleException(ex)
'-- Build the detail element of the SOAP fault.
Dim doc As New System.Xml.XmlDocument
Dim node As System.Xml.XmlNode = doc.CreateNode(XmlNodeType.Element, _
SoapException.DetailElementName.Name, _
SoapException.DetailElementName.Namespace)
'-- append our error detail string to the SOAP detail element
Dim details As System.Xml.XmlNode = doc.CreateNode(XmlNodeType.Element, _
"ExceptionInfo", _
SoapException.DetailElementName.Namespace)
details.InnerText = ueh.ExceptionToString(ex)
node.AppendChild(details)
'-- re-throw the exception so we can package additional info
Throw New SoapException("Unhandled Exception: " & ex.Message, _
SoapException.ClientFaultCode, _
Context.Request.Url.ToString, node)
End Sub
And it really does work. This is a capture of a generic exception using a network sniffer, so we're looking at raw HTTP traffic here. Before:
HTTP/1.1 500 Internal Server Error.
Date: Wed, 26 May 2004 05:12:08 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 1.1.4322
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Content-Length: 488
<?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>Server was unable to process request. --> Object reference not set to an instance of an object.</faultstring>
<detail />
</soap:Fault>
</soap:Body>
</soap:Envelope>
After:
HTTP/1.1 500 Internal Server Error.
Date: Wed, 26 May 2004 05:09:20 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 1.1.4322
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Content-Length: 782
<?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>SoapException</faultstring>
<faultactor>http://192.168.168.10/WebService1/Service1.asmx</faultactor>
<detail>
<ExceptionType>System.NullReferenceException</ExceptionType>
<ExceptionMessage>Object reference not set to an instance of an object.</ExceptionMessage>
<ExceptionTrace>at WebService1.Service1.HelloException2() in \\HOMESERVER\wwwroot$\WebService1\Service1.asmx.vb:line 70</ExceptionTrace>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Notice the <detail> element is fully populated, and the entire <soap:Fault> element is much more informative-- cool!
a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service09172002.asp"http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service09172002.asp/a
So what do you do when you deploy the Web service? You need to open up Web.config and edit the /configuration/system.web/customErrors/@mode attribute. By default, this attribute is set to RemoteOnly. The @mode attribute accepts two other values as well:
On
Off
The On setting tells ASP.NET not to add the stack trace information to any Faults. RemoteOnly causes the extra information to show up for clients on the same server and hides the information for remote users. When set to Off, the extra information shows up for all calls to the Web service. This is the same behavior you will see for Web pages. By setting the @mode attribute to On and throwing the same exception, I will get the following Fault instead:
I just set @mode attribute to "Off" while developing. Then when catching exceptions on the client side the exception is filled with method calls, line numbers, stack trace, etc.
Ah, interesting. I am familiar with the error setting for ASP.NET apps; I didn't realize there was a similar setting specific to web services.
Jeff Atwood on August 15, 2005 3:35 AMDownload/order the WeFly247 application from Microsoft. (www.learn247.net)
They have made a quite elegant solution where they use the soap formatter (System.Runtime.Serialization.Formatters.Soap) to serialize and deserialize the exception.
Ralf de Kleine on November 24, 2005 8:00 AMI do not only want to see the exceptions when developing. I need to catch them with a "Application_Error" solution. Application_Error catches allmost all errors. aspx, ashx, master, and even 404 errors when the file does not exist.
I cannot find words for what I think of Microsoft after reading "there really is no good way to generically handle unhandled exception in .NET web services".
Let us do it the windows way. Just wait for a new version and hope for the best.
Morten on September 27, 2006 6:32 AMActually, I did find a way to handle web service exceptions globally. It's documented in this CodeProject article..
http://www.codeproject.com/aspnet/ASPNETExceptionHandling.asp
Scroll down to "Unhandled Exceptions in ASP.NET Web Services".
Jeff Atwood on September 27, 2006 10:49 AMMy application uses web services over remoting, and the details I add in the xmlNode of the SoapException do not show on the client side.
I resigned myself into sending all error info in one string.
Anyone has an idea of what may be wrong?
Thanks.
throw new SoapException("Exception message here", new XmlQualifiedName("qualified name here, not empty !"));
adrian on December 22, 2006 2:02 AMThe comments to this entry are closed.
|
|
Traffic Stats |