我可以通过使用.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);
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,以及在标头中写入的相应状态代码。
希望这可以帮助。