I figured out today that .NET WebServices do not fire HttpApplication.Error events on exceptions. This is because WebServices require their own error handlers around the WebService class so that the Exceptions can be wrapped up properly into SoapExceptions and sent back to the client in SOAP formatted messages.
Unfortunately this nullifies my generic error handling and logging routines that normally fire in response to exceptions. My Web apps handle errors through the HttpApplication.Error handler in Global.asax which allows logging and error display. Unfortunately Web Services don’t fire HttpApplication.Error on unhandled exceptions, so this scheme doesn’t work.
Ran a quick search on Google trying to figure out whether there is a common error handling handler, but offhand couldn’t find it. The question becomes how do you deal with unhandled Web Service exceptions generically?
I’m probably missing some global error handling point, but I needed this done now so my not so clean solution for now is to wrap the entire method into a custom SoapException exception block and use this custom SoapException to log my request. This handler is application specific but can be applied globally – the primary purpose is to log errors.
public class LoggingSoapException : SoapException
{
public LoggingSoapException(string ErrorMessage) :
base(ErrorMessage,SoapException.ServerFaultCode)
{
this.LogException(ErrorMessage,this);
}
public LoggingSoapException(string ErrorMessage,Exception ex) :
base(ErrorMessage,SoapException.ServerFaultCode)
{
this.LogException(ErrorMessage,ex);
}
protected void LogException(string ErrorMessage,Exception ex)
{
if (ex == null)
ex = this;
WebErrorHandler Handler = new WebErrorHandler(ex);
// *** Log the error if specified
if (App.Configuration.LogErrors == LogType.Xml)
{
Handler.LogFileName = App.Configuration.XmlErrorLogFile;
Handler.LogErrorToXml(true);
}
else if (App.Configuration.LogErrors == LogType.SqlServer)
{
Handler.LogErrorToSql(App.Configuration.ConnectionString);
}
}
}
Here’s an example of how this can be used:
/// <summary>
/// Submits a bug to the server. The bug is forwarded via email and
/// </summary>
/// <param name="NewBug"></param>
/// <returns></returns>
[WebMethod(Description="Submits a bug to be stored to the database and emailed to the configured recipients")]
public int SubmitBug( BugreportsEntity NewBug )
{
try
{
BugReport Bug = new BugReport();
Bug.Pk = 0;
if (!Bug.New() )
{
throw new LoggingSoapException(Bug.ErrorMessage);
return -1;
}
// *** Assign our new Pk and update the timestamp to server local time
NewBug.Pk = Bug.Pk;
NewBug.Entered = DateTime.Now;
NewBug.Statusupdate = DateTime.Now;
// *** Move the Incomign proxy data into a new bug
NewBug.SynchronizeDataRowToProperties( Bug.DataRow );
Bug.SendEmail();
System.Threading.Thread.Sleep(1000);
if (!Bug.Save())
{
throw new LoggingSoapException(Bug.ErrorMessage);
return -1;
}
return Bug.Pk;
}
catch(Exception ex)
{
throw new LoggingSoapException(ex.Message,ex);
}
}
Unfortunately this approach is not a no touch implementation as you need to wrap methods in an exception block, but it works for the moment. My immediate concern is that I have some odd failures in one of my services and I need to track these down since I haven’t seen these sorts of failures in my dev environment.
If anybody knows a more generic mechanism that’d be handy <g>…
Other Posts you might also like