生成通用“服务不可用”消息的ELMAHexception

我正在尝试创建一个可用性页面,它检查站点使用的所有服务,将每个检查包装在try / catch中,然后向用户显示任何失败。 其中一项服务是ELMAH,所以我打电话来仔细检查我们是否可以成功记录错误。

控制器:

var a = new AvailabilityModel(); try { a.ElmahConnectionString = ConfigurationManager.ConnectionStrings["elmah-sqlserver"].ConnectionString; Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Elmah availability test")); a.ElmahSuccess = true; } catch (Exception ex) { a.ElmahSuccess = false; a.ElmahException = ex; Response.StatusCode = 503; } return View(a); 

当ELMAH成功时,一切都很顺利。 当它抛出任何类型的错误(数据库权限等)时,我得到一个错误,这个错误不是由try / catch或任何正常的错误捕获部分捕获的:ASP.NET MVC HandleErrorcustomErrors重定向,甚至system.webServer httpErrors 。 显示器不是正常的IIS通用消息,而是我看到一行说“服务不可用”。

响应:

 LTSB-W34511 C:\s\d\build % curl -i http://server/test/availability HTTP/1.1 503 Service Unavailable Cache-Control: public, max-age=14400, s-maxage=0 Content-Type: text/html Server: Microsoft-IIS/7.5 X-AspNetMvc-Version: 4.0 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Wed, 06 Aug 2014 15:46:55 GMT Content-Length: 27 The service is unavailable. 

就是这样。 至少我知道我的可用性不起作用,但我想至少向用户显示它是导致问题的ELMAH,并显示它试图使用的连接字符串。 所以,我需要以某种方式捕获此exception。

我尝试过多种不同的方式来调整我的web.config,但我怀疑ELMAH将自己插入模块管道的方式让我无法处理问题。

编辑:

为了澄清,这是一个简化的例子。 我不打算将此信息公开给最终用户。 此可用性页面仅供将来解决未来问题的内部用户使用。

ELMAH只是相关应用程序使用的服务/数据库之一,我希望为管理员提供快速的仪表板视图,了解上下的内容。 如果ELMAH错误导致这个insta-503,我不能这样做。

好的,基本上没有任何代码就不可能。 除非你追踪它,否则Elmah中的Raise方法不会让你看到任何错误:

 // ErrorLogModule.LogException try { Error error = new Error(e, context); ErrorLog errorLog = this.GetErrorLog(context); error.ApplicationName = errorLog.ApplicationName; string id = errorLog.Log(error); errorLogEntry = new ErrorLogEntry(errorLog, id, error); } catch (Exception value) { Trace.WriteLine(value); } 

但是,当事件成功记录时,ErrorLogModule将调用已logged事件,以便让潜在的侦听器知道日志记录成功。 因此,让我们快速编写一个自定义类,它将覆盖ErrorLogModule中的一些方法,并允许我们注意到事件未被记录:

 public class CustomErrorLogModule: Elmah.ErrorLogModule { public Boolean SomethingWasLogged { get; set; } protected override void OnLogged(Elmah.ErrorLoggedEventArgs args) { SomethingWasLogged = true; base.OnLogged(args); } protected override void LogException(Exception e, HttpContext context) { SomethingWasLogged = false; base.LogException(e, context); if (!SomethingWasLogged) { throw new InvalidOperationException("An error was not logged"); } } } 

使用配置文件中的CustomErrorLogModule交换ErrorLogModule ,当发生错误时,Elmah会抱怨; 调用Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("test")); 在测试页面中,可以将InvalidOperationException("An error was not logged")抛出调用。


如果要返回尝试记录exception时发生的确切exception,可以使用ErrorLogModule在exception发生时跟踪exception的事实。 创建一个监听器类:

 public class ExceptionInterceptor : DefaultTraceListener { public Exception TracedException { get; set; } public override void WriteLine(object o) { var exception = o as Exception; if (exception != null) { TracedException = exception; } } } 

然后你的LogException方法变成了

 protected override void LogException(Exception e, HttpContext context) { var exceptionListener = new ExceptionInterceptor(); Trace.Listeners.Add(exceptionListener); try { SomethingWasLogged = false; base.LogException(e, context); if (!SomethingWasLogged) { throw exceptionListener.TracedException; } } finally { Trace.Listeners.Remove(exceptionListener); } } 

编辑:或者即使你想尽可能简洁

 public class ExceptionInterceptor : DefaultTraceListener { public override void WriteLine(object o) { var exception = o as Exception; if (exception != null) { throw exception; } } } // snip... LogException in your CustomErrorLogModule protected override void LogException(Exception e, HttpContext context) { var exceptionListener = new ExceptionInterceptor(); Trace.Listeners.Add(exceptionListener); try { base.LogException(e, context); } finally { Trace.Listeners.Remove(exceptionListener); } } 

最后一句话:检查服务可用性的方式有一种气味,您将使用可能不是所需行为的测试exception来处理错误数据库。 我知道你的目标是检查整个日志链,但也许还有其他方法可以做到; 我真的不知道你的背景,所以我不会再评论,但不要犹豫,想一想。

无论如何,这些更改应该让您收到您需要的例外。


重要的编辑 :非常重要的一点:您可能希望向CustomErrorLogModule添加一个触发器,以便在您不进行测试时不会抛出。 您在Elmah中观察到的弹性通常是一件好事,因为您不希望诊断平台导致可能需要其他诊断的问题。 这就是Elmah或日志记录框架不抛出的原因,这就是为什么你应该使exception重新抛出机制可触发,这样你的程序就不必在Elmah中引发exception时看到它的步骤。

不不不! 切勿向用户显示连接字符串,也不要告诉他们问题所在。 这样做是一个严重的安全漏洞。 简单地说,不要这样做。 修复Elmah的潜在问题。

error handling管道中的问题非常糟糕,因为它会导致它尝试处理生成的新错误,这基本上会导致循环。 ASP.NET引擎识别出严重错误,因此它提供了一个通用的“服务不可用”消息。 检查服务器上的事件日志以找出潜在的Elmah错误并进行更正。