通过使用 .NET 3.5 在 asp.net webforms 中使用以下设置,我能够解决此问题。
我实现的模式绕过了 web.config 中 .NET 的自定义重定向解决方案,因为我编写了自己的模式来处理标题中包含正确 HTTP 状态代码的所有场景。
首先,web.config 的 customErrors 部分如下所示:
<customErrors mode="RemoteOnly" defaultRedirect="~/error.htm" />
此设置可确保将 CustomErrors 模式设置为 on,这是我们稍后需要的设置,并为 error.htm 的 defaultRedirect 提供了一个 all-else-fails 选项。当我没有针对特定错误的处理程序时,这将派上用场,或者数据库连接中断。
其次,这是全局 asax 错误事件:
protected void Application_Error(object sender, EventArgs e)
{
HandleError();
}
private void HandleError()
{
var exception = Server.GetLastError();
if (exception == null) return;
var baseException = exception.GetBaseException();
bool errorHandled = _applicationErrorHandler.HandleError(baseException);
if (!errorHandled) return;
var lastError = Server.GetLastError();
if (null != lastError && HttpContext.Current.IsCustomErrorEnabled)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(lastError.GetBaseException());
Server.ClearError();
}
}
此代码将处理错误的责任转交给另一个类。如果错误没有得到处理并且 CustomErrors 被打开,这意味着我们有一个案例,我们正在生产中并且不知何故没有处理错误。我们将在此处清除它以防止用户看到它,但将其登录到 Elmah 以便我们知道发生了什么。
applicationErrorHandler 类如下所示:
public bool HandleError(Exception exception)
{
if (exception == null) return false;
var baseException = exception.GetBaseException();
Elmah.ErrorSignal.FromCurrentContext().Raise(baseException);
if (!HttpContext.Current.IsCustomErrorEnabled) return false;
try
{
var behavior = _responseBehaviorFactory.GetBehavior(exception);
if (behavior != null)
{
behavior.ExecuteRedirect();
return true;
}
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
return false;
}
此类本质上使用命令模式来为发出的错误类型定位适当的错误处理程序。在此级别使用 Exception.GetBaseException() 很重要,因为几乎每个错误都将包装在更高级别的异常中。例如,从任何 aspx 页面执行“throw new System.Exception()”将导致在此级别收到 HttpUnhandledException,而不是 System.Exception。
“工厂”代码很简单,如下所示:
public ResponseBehaviorFactory()
{
_behaviors = new Dictionary<Type, Func<IResponseBehavior>>
{
{typeof(StoreException), () => new Found302StoreResponseBehavior()},
{typeof(HttpUnhandledException), () => new HttpExceptionResponseBehavior()},
{typeof(HttpException), () => new HttpExceptionResponseBehavior()},
{typeof(Exception), () => new Found302DefaultResponseBehavior()}
};
}
public IResponseBehavior GetBehavior(Exception exception)
{
if (exception == null) throw new ArgumentNullException("exception");
Func<IResponseBehavior> behavior;
bool tryGetValue = _behaviors.TryGetValue(exception.GetType(), out behavior);
//default value here:
if (!tryGetValue)
_behaviors.TryGetValue(typeof(Exception), out behavior);
if (behavior == null)
Elmah.ErrorSignal.FromCurrentContext().Raise(
new Exception(
"Danger! No Behavior defined for this Exception, therefore the user might have received a yellow screen of death!",
exception));
return behavior();
}
最后,我有了一个可扩展的错误处理方案设置。在定义的每一个“行为”中,我都有一个错误类型的自定义实现。例如,将检查 Http 异常的状态代码并进行适当处理。404 状态代码将需要 Server.Transfer 而不是 Request.Redirect,以及在标头中写入的适当状态代码。
希望这可以帮助。