ASP.NET MVC中的error handling
我怎样才能正确处理从ASP.NET MVC中的控制器引发的exception? HandleError
属性似乎只处理由MVC基础设施抛出的exception,而不是由我自己的代码引发的exception。
使用这个web.config
<customErrors mode="On"> <error statusCode="401" redirect="/Errors/Http401" /> </customErrors>
用下面的代码
namespace MvcApplication1.Controllers { [HandleError] public class HomeController : Controller { public ActionResult Index() { // Force a 401 exception for testing throw new HttpException(401, "Unauthorized"); } } }
不会导致我所希望的。 相反,我得到了通用的ASP.NET错误页面,告诉我修改我的web.config来查看实际的错误信息。 但是,如果不是抛出一个exception,我返回一个无效的视图,我得到/Shared/Views/Error.aspx页面:
return View("DoesNotExist");
像上面所做的那样在控制器中抛出exception似乎绕过了HandleError
所有function,那么创build错误页面的正确方法是什么,以及如何与MVC基础架构打好关系?
Controller.OnException(ExceptionContext context)
。 覆盖它。
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); }
感谢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。
HandleError属性似乎只处理由MVC基础设施抛出的exception,而不是由我自己的代码引发的exception。
这是错误的。 事实上,HandleError只会“处理”抛出在你自己的代码中的exception,或者是由你自己的代码调用的代码。 换句话说,只有您的操作在调用堆栈中的exception。
你所看到的行为的真正解释是你抛出的具体exception。 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; }
我不认为你将能够显示具有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); } }
}
另外一种可能性(你的情况并非如此),其他读者可能正在经历的是你的错误页面本身正在抛出一个错误,或者没有实现:
System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>
如果是这种情况,那么你会得到默认的错误页面(否则你会得到一个无限循环,因为它会不断尝试将自己发送到您的自定义错误页面)。 这对我来说并不是显而易见的。
这个模型是发送到错误页面的模型。 如果您的错误页面使用与您网站其他部分相同的主页面,并且需要任何其他模型信息,那么您将需要创build您自己的[HandleError]
types的属性或重写OnException
或其他内容。
我select了Controller.OnException()方法,对我来说这是合乎逻辑的select – 因为我select了ASP.NET MVC,所以我宁愿留在框架级别,并尽可能避免与底层机制混淆。
我遇到了以下问题:
如果在视图内发生exception,则来自该视图的部分输出将与错误消息一起出现在屏幕上。
我通过在设置filterContext.Result之前清除响应来解决这个问题 – 像这样:
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); } }
Jeff Atwood的用户友好的exception处理模块非常适合MVC。 你可以在你的web.config中完全configuration它,根本没有MVC项目源代码的变化。 但是,它需要一个小的修改来返回原始的HTTP状态,而不是200
状态。 看到这个相关的论坛post 。
基本上,在Handler.vb中,可以添加如下内容:
' In the header... Private _exHttpEx As HttpException = Nothing ' At the top of Public Sub HandleException(ByVal ex As Exception)... HttpContext.Current.Response.StatusCode = 500 If TypeOf ex Is HttpException Then _exHttpEx = CType(ex, HttpException) HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode() End If
- WCF ExceptionShielding错误ID不匹配与handlingInstanceId传递给处理程序
- exception传播指导(Java)
- locking的对象是否locking,如果内部发生exception?
- 在64位版本的Windows上的WinForms应用程序中,VS2010不显示未处理的exception消息
- 在pydev中打破例外
- JDBC驱动程序在空的ResultSet上抛出“ResultSet Closed”exception
- 在Python中,如何捕获警告,就像它们是exception?
- Androidexception处理最佳实践?
- 意外的types – 序列化exception