Asp.net mvc ASP.NET MVC中的错误处理
如何正确处理ASP.NET MVC中控制器引发的异常?Asp.net mvc ASP.NET MVC中的错误处理,asp.net-mvc,exception,Asp.net Mvc,Exception,如何正确处理ASP.NET MVC中控制器引发的异常?HandleError属性似乎只处理MVC基础设施引发的异常,而不是我自己的代码引发的异常 使用此web.config <customErrors mode="On"> <error statusCode="401" redirect="/Errors/Http401" /> </customErrors> 没有得到我所希望的结果。相反,我会得到一个通用的ASP.NET错误页面,告诉我修改web.
HandleError
属性似乎只处理MVC基础设施引发的异常,而不是我自己的代码引发的异常
使用此web.config
<customErrors mode="On">
<error statusCode="401" redirect="/Errors/Http401" />
</customErrors>
没有得到我所希望的结果。相反,我会得到一个通用的ASP.NET错误页面,告诉我修改web.config以查看实际的错误信息。但是,如果不是引发异常,而是返回无效视图,则会得到/Shared/Views/Error.aspx页面:
return View("DoesNotExist");
在控制器中抛出异常,就像我在上面所做的那样,似乎绕过了所有的HandleError
功能,那么创建错误页面的正确方法是什么?如何更好地使用MVC基础设施
HandleError属性似乎只处理MVC基础设施引发的异常,而不是我自己的代码引发的异常
这是错误的。事实上,HandleError只会“处理”您自己的代码或您自己的代码调用的代码中抛出的异常。换句话说,只有您的操作在调用堆栈中的异常才会出现
你看到的行为的真正解释是你抛出的特定异常。HandleError与HttpException的行为不同。从源代码:
// If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
// ignore it.
if (new HttpException(null, exception).GetHttpCode() != 500) {
return;
}
Controller.OnException(ExceptionContext上下文)
。覆盖它
protected override void OnException(ExceptionContext filterContext)
{
// Bail if we can't do anything; app will crash.
if (filterContext == null)
return;
// since we're handling this, log to elmah
var ex = filterContext.Exception ?? new Exception("No further information exists.");
LogException(ex);
filterContext.ExceptionHandled = true;
var data = new ErrorPresentation
{
ErrorMessage = HttpUtility.HtmlEncode(ex.Message),
TheException = ex,
ShowMessage = !(filterContext.Exception == null),
ShowLink = false
};
filterContext.Result = View("ErrorPage", data);
}
我认为您不能基于带有HandleError属性的HttpCode显示特定的ErrorPage,我更愿意为此使用HttpModule。假设我有文件夹“ErrorPages”,其中每个特定错误都有不同的页面,并且映射在web.config中指定,与常规web表单应用程序相同。下面是用于显示错误页面的代码:
public class ErrorHandler : BaseHttpModule{
public override void OnError(HttpContextBase context)
{
Exception e = context.Server.GetLastError().GetBaseException();
HttpException httpException = e as HttpException;
int statusCode = (int) HttpStatusCode.InternalServerError;
// Skip Page Not Found and Service not unavailable from logging
if (httpException != null)
{
statusCode = httpException.GetHttpCode();
if ((statusCode != (int) HttpStatusCode.NotFound) && (statusCode != (int) HttpStatusCode.ServiceUnavailable))
{
Log.Exception(e);
}
}
string redirectUrl = null;
if (context.IsCustomErrorEnabled)
{
CustomErrorsSection section = IoC.Resolve<IConfigurationManager>().GetSection<CustomErrorsSection>("system.web/customErrors");
if (section != null)
{
redirectUrl = section.DefaultRedirect;
if (httpException != null)
{
if (section.Errors.Count > 0)
{
CustomError item = section.Errors[statusCode.ToString(Constants.CurrentCulture)];
if (item != null)
{
redirectUrl = item.Redirect;
}
}
}
}
}
context.Response.Clear();
context.Response.StatusCode = statusCode;
context.Response.TrySkipIisCustomErrors = true;
context.ClearError();
if (!string.IsNullOrEmpty(redirectUrl))
{
context.Server.Transfer(redirectUrl);
}
}
公共类错误处理程序:BaseHttpModule{
公共覆盖无效OnError(HttpContextBase上下文)
{
异常e=context.Server.GetLastError().GetBaseException();
HttpException HttpException=e作为HttpException;
int statusCode=(int)HttpStatusCode.InternalServerError;
//跳过未找到的页面和记录的服务不可用
if(httpException!=null)
{
statusCode=httpException.GetHttpCode();
if((statusCode!=(int)HttpStatusCode.NotFound)和&(statusCode!=(int)HttpStatusCode.ServiceUnavailable))
{
日志异常(e);
}
}
字符串重定向URL=null;
if(context.IsCustomErrorEnabled)
{
CustomErrorsSection=IoC.Resolve().GetSection(“system.web/customErrors”);
if(节!=null)
{
redirectUrl=section.DefaultRedirect;
if(httpException!=null)
{
如果(section.Errors.Count>0)
{
CustomError item=section.Errors[statusCode.ToString(Constants.CurrentCulture)];
如果(项!=null)
{
重定向URL=item.Redirect;
}
}
}
}
}
context.Response.Clear();
context.Response.StatusCode=状态码;
context.Response.tryskipiiscustomerors=true;
context.ClearError();
如果(!string.IsNullOrEmpty(重定向URL))
{
context.Server.Transfer(重定向URL);
}
}
}多亏了kazimanzurrashaid,我在Global.asax.cs上完成了以下工作:
protected void Application_Error()
{
Exception unhandledException = Server.GetLastError();
HttpException httpException = unhandledException as HttpException;
if (httpException == null)
{
Exception innerException = unhandledException.InnerException;
httpException = innerException as HttpException;
}
if (httpException != null)
{
int httpCode = httpException.GetHttpCode();
switch (httpCode)
{
case (int) HttpStatusCode.Unauthorized:
Response.Redirect("/Http/Error401");
break;
}
}
}
根据我需要支持的任何其他HTTP错误代码,我将能够向HttpContoller添加更多页面。阅读本文的其他人可能遇到的另一种可能性(在您的情况下不是这样)是您的错误页面本身抛出错误,或者未实现:
System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>
System.Web.Mvc.ViewPage
如果是这种情况,那么您将得到默认的错误页面(否则您将得到一个无限循环,因为它将不断尝试将自己发送到您的自定义错误页面)。这对我来说不是很明显
此模型是发送到错误页面的模型。如果您的错误页面使用与站点其他部分相同的母版页,并且需要任何其他模型信息,则您需要创建自己的
[HandleError]
属性类型或覆盖OneException
或其他内容。我选择了Controller.OneException()方法,对我来说,这是一个合乎逻辑的选择——因为我选择了ASP.NETMVC,所以我更喜欢停留在框架级别,如果可能的话,避免弄乱底层机制
我遇到了以下问题:
如果视图中发生异常,则该视图的部分输出将与错误消息一起出现在屏幕上
在设置filterContext.Result之前,我通过清除响应修复了此问题-如下所示:
filterContext.HttpContext.Response.Clear(); // gets rid of any garbage
filterContext.Result = View("ErrorPage", data);
希望这能为其他人节省一些时间:-)杰夫·阿特伍德的作品对MVC非常有用。您可以完全在web.config中配置它,而无需对MVC项目源代码进行任何更改。但是,它需要一个小的修改来返回原始HTTP状态,而不是200
状态。见此相关报道
基本上,在Handler.vb中,您可以添加如下内容:
标题中的“”。。。
Private _exhttppexas HttpException=无
'在公共子句柄异常的顶部(ByVal ex作为异常)。。。
HttpContext.Current.Response.StatusCode=500
如果TypeOf ex是HttpException,那么
_exHttpEx=CType(ex,HttpException)
HttpContext.Current.Response.StatusCode=\u exhttppex.GetHttpCode()
如果结束
您已经指出,如果没有解决无法为HTTP错误代码提供错误处理的真正问题,我的一个陈述是不正确的。我可以解释发生了什么,但我需要更多信息,以便告诉您如何正确处理应用程序。HandleError在操作中工作,并且通常不会在操作中抛出HttpExceptions。而不是猜测你到底是什么
filterContext.HttpContext.Response.Clear(); // gets rid of any garbage
filterContext.Result = View("ErrorPage", data);
protected override void OnException (ExceptionContext filterContext )
{
if (filterContext != null && filterContext.Exception != null)
{
filterContext.ExceptionHandled = true;
this.View("Error").ViewData["Exception"] = filterContext.Exception.Message;
this.View("Error").ExecuteResult(this.ControllerContext);
}
}