我正在尝试创建一个可用性页面,该页面检查站点使用的所有服务,将每个检查包装在 try/catch 中,然后向用户显示任何失败。其中一项服务是 ELMAH,因此我调用该服务是为了仔细检查我们是否可以成功记录错误。
Controller :
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 HandleError
、customErrors
重定向,甚至 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 导致了问题,并显示它尝试使用的连接字符串。所以,我需要以某种方式捕获这个异常。
我尝试了多种不同的方式调整我的 web.config,但我怀疑 ELMAH 将自身插入模块管道的方式存在某种问题,这阻止了我处理该问题。
编辑:
澄清一下,这是一个简化的示例。我不打算向最终用户公开此信息。此可用性页面仅适用于对 future 问题进行故障排除的内部用户。
ELMAH 只是相关应用程序使用的服务/数据库之一,我想为管理员提供一个类似于仪表板的快速 View ,显示上行和下行的情况。如果 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");
}
}
}
将配置文件中的 ErrorLogModule
与 CustomErrorLogModule
交换,当发生错误时,Elmah 会提示;在测试页面中调用 Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("test"));
会导致 InvalidOperationException("An error was notlogging")
被排除在通话之外。
如果您想获取在尝试记录异常时发生的确切异常,您可以利用 ErrorLogModule 在异常发生时对其进行跟踪的事实。创建监听器类:
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 或日志框架不会抛出异常,这就是为什么您应该使异常重新抛出机制可触发,这样您的程序在 Elmah 中引发异常时就不必监视其步骤。
关于c# - ELMAH 异常生成通用 "The service is unavailable"消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25164866/