如何管理MVC控制器中的所有未处理错误

时间:2010-12-21 20:19:15

标签: c# .net asp.net-mvc

我在Global.asax中尝试

protected void Application_Start()
    {
      AreaRegistration.RegisterAllAreas();

      RegisterGlobalFilters(GlobalFilters.Filters);
      RegisterRoutes(RouteTable.Routes);
      this.Error += new EventHandler(MvcApplication_Error);
    }

    public void MvcApplication_Error(object sender, EventArgs e)
    {
      throw new NotImplementedException();
    }

但事件从未被提出过!

4 个答案:

答案 0 :(得分:8)

优雅处理未处理异常的最简单方法是(A)使用Elmah挂钩未处理的异常并记录它们,以及(B)使用global.asax的Application_Error()方法捕获未处理的异常。这是我的:

    protected void Application_Error( object sender , EventArgs e )
    {
        // only do something special if the request is not from the local machine.
        if ( !Request.IsLocal )
        {
            Exception     exception     = Server.GetLastError() ;
            HttpException httpException = exception as HttpException ;
            RouteData     routeData     = new RouteData() ;

            routeData.Values.Add( "controller" , "Error" ) ;

            if ( httpException != null )
            {
                int httpStatusCode = httpException.GetHttpCode() ;

                switch ( httpStatusCode )
                {
                case 404 : routeData.Values.Add( "action" , "Http404FileNotFound"        ) ; break ;
                default  : routeData.Values.Add( "action" , "HttpError"                  ) ; break ;
                }
                routeData.Values.Add( "exception" , httpException ) ;
            }
            else
            {
                routeData.Values.Add( "action" , "Http500InternalServerError" ) ;
                routeData.Values.Add( "exception" , exception ) ;
            }

            Response.Clear() ;
            Server.ClearError() ;

            HttpContextBase contextWrapper  = new HttpContextWrapper( Context ) ;
            RequestContext  newContext      = new RequestContext( contextWrapper , routeData ) ;
            IController     errorController = new ErrorController() ;
            errorController.Execute( newContext ) ;
        }

        return ;
    }

以上方法:

  • 对于本地请求(例如,开发人员的机器),不处理异常并且ASP.Net回退标准黄屏O'Death。

  • 通过显示(不重定向 - 用户看到原始URL)处理远程请求,这是一个友好的错误页面,不会泄漏实现信息(如堆栈跟踪等)。逻辑如下:

    • 如果异常可以转换为HttpException,则会检查HTTP状态(响应)代码。 Http状态代码404显示我们的“未找到资源”视图,具有404响应状态;其他HttpExceptions获得一个不同的“Http Error”视图,将响应状态设置为500(内部服务器错误)。

    • 如果无法将异常强制转换为HttpException,则会返回“内部错误”视图,该视图还会将响应状态设置为500(内部服务器错误)。

轻松!您可能希望在适当的地方使用log4net(例如,在抛出异常时)记录可能有助于调试异常根本原因的任何上下文数据。

答案 1 :(得分:7)

您可以使用Controller MetaData中已有的OnException方法

protected override void OnException(ExceptionContext filterContext)
    {
      //Build of error source.
      string askerUrl = filterContext.RequestContext.HttpContext.Request.RawUrl;
      Exception exToLog = filterContext.Exception;
      exToLog.Source = string.Format("Source : {0} {1}Requested Path : {2} {1}", exToLog.Source, Environment.NewLine, askerUrl);
      //Log the error
      ExceptionLogger.Publish(exToLog, "unhandled", filterContext.RequestContext.HttpContext.Request.ServerVariables.ToString(), askerUrl);
      //Redirect to error page : you must feed filterContext.Result to cancel already executing Action
      filterContext.ExceptionHandled = true;
      filterContext.Result = new ErrorController().ManageError(ErrorResources.GeneralErrorPageTitle, ErrorResources.GeneralErrorTitle, ErrorResources.GeneralErrorInnerBody, exToLog);
      base.OnException(filterContext);
    }

答案 2 :(得分:2)

除了Nico的建议,您还可以使用控制器上的属性,例如......

    [ExceptionHandler("DefaultError", typeof(DivideByZeroException))]
public class HomeController : N2Controller
{
   [ControllerAction, ExceptionHandler("Error")]
   public void Index()
   {

   }
}

Example source.

这允许您在需要时对异常处理程序进行更细粒度的控制(每个方法),或者在基本控制器中只有一个属性来处理所有错误。

答案 3 :(得分:0)

为了使其工作,您必须在MvcApplication构造函数中注册事件:

public MvcApplication()
{
    Error += MvcApplication_Error;
}

private void MvcApplication_Error(object sender, EventArgs e)
{
    //Do your stuff
}