2012-01-24 22 views
5

我已經開始在VS10的MVC 3模板項目和修改的global.asax.cs這樣:HandleErrorAttribute不工作

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
    filters.Add(new HandleErrorAttribute { ExceptionType = typeof(DivideByZeroException), View = "DivideByZeroException", Order = 1 }); 
    filters.Add(new HandleErrorAttribute { View = "AllOtherExceptions", Order = 2 }); 
} 

到Web.config中我加:

<customErrors mode="On"> 

然後創建相應的視圖,並最終添加了DivideByZero-throw到其中一個動作。

結果:呈現AllOtherExceptions視圖。

回答

21

雖然我討厭不同意達林所說的任何話,但他在這個問題上是錯誤的。

設置屬性沒有問題(這是你的假設這樣做)。

原始代碼沒有按預期工作的唯一原因是因爲您的Order設置錯誤。

MSDN

的OnActionExecuting(ActionExecutingContext), OnResultExecuting(ResultExecutingContext)和 OnAuthorization(AuthorizationContext)過濾前的順序運行。 OnResultExecuting(ResultExecutingContext)和 OnException(ExceptionContext)過濾器以相反的順序運行。

所以你的通用AllOtherExceptions過濾器需要是最低的Order號碼,而不是最高的。

希望下次有所幫助。

+0

聽起來像你有案例,恐懼!既然Darin確實解決了我的問題,那麼你必須用upvotes來對付這個問題。 – Martin

+0

感謝你 - 應該是答案! –

+0

更改了答案... – Martin

8

註冊全局操作過濾器時,不應該設置屬性。你可以寫一個自定義的處理錯誤過濾器:

public class MyHandleErrorAttribute : FilterAttribute, IExceptionFilter 
{ 
    public void OnException(ExceptionContext filterContext) 
    { 
     if (!filterContext.IsChildAction && (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled)) 
     { 
      Exception innerException = filterContext.Exception; 
      if ((new HttpException(null, innerException).GetHttpCode() == 500)) 
      { 
       var viewName = "AllOtherExceptions"; 
       if (typeof(DivideByZeroException).IsInstanceOfType(innerException)) 
       { 
        viewName = "DivideByZeroException"; 
       } 

       string controllerName = (string)filterContext.RouteData.Values["controller"]; 
       string actionName = (string)filterContext.RouteData.Values["action"]; 
       HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName); 
       ViewResult result = new ViewResult 
       { 
        ViewName = viewName, 
        ViewData = new ViewDataDictionary<HandleErrorInfo>(model), 
        TempData = filterContext.Controller.TempData 
       }; 
       filterContext.Result = result; 
       filterContext.ExceptionHandled = true; 
       filterContext.HttpContext.Response.Clear(); 
       filterContext.HttpContext.Response.StatusCode = 500; 
       filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
      } 
     } 
    } 
} 

,然後註冊它:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
    filters.Add(new MyHandleErrorAttribute()); 
} 
+3

它當然有效。如何在註冊全局操作過濾器時無法設置屬性? – Martin

0

下面做檢查恐懼的答案。它當然更簡單,如果它有效。

由於它是在幾個星期後發佈的,所以我的過濾器使用Darins響應和合並Elmah報告的方式最終拼寫出來,代碼來自this主題。

我仍然不知道爲什麼你不能在全局動作過濾器上設置屬性。

public class MyHandleErrorAttribute : FilterAttribute, IExceptionFilter 
{ 
    public void OnException(ExceptionContext filterContext) 
    { 
     if (!filterContext.IsChildAction && 
      (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled)) 
     { 
      var innerException = filterContext.Exception; 
      if ((new HttpException(null, innerException).GetHttpCode() == 500)) 
      { 
       var viewName = "GeneralError"; 
       if (typeof (HttpAntiForgeryException).IsInstanceOfType(innerException)) 
        viewName = "SecurityError"; 

       var controllerName = (string) filterContext.RouteData.Values["controller"]; 
       var actionName = (string) filterContext.RouteData.Values["action"]; 
       var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName); 
       var result = new ViewResult 
             { 
              ViewName = viewName, 
              ViewData = new ViewDataDictionary<HandleErrorInfo>(model), 
              TempData = filterContext.Controller.TempData 
             }; 

       filterContext.Result = result; 
       filterContext.ExceptionHandled = true; 
       filterContext.HttpContext.Response.Clear(); 
       filterContext.HttpContext.Response.StatusCode = 500; 
       filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 

//From here on down, this is all code for Elmah-reporting. 
       var version = Assembly.GetExecutingAssembly().GetName().Version; 
       filterContext.Controller.ViewData["Version"] = version.ToString(); 

       var e = filterContext.Exception; 
       if (!filterContext.ExceptionHandled // if unhandled, will be logged anyhow 
        || RaiseErrorSignal(e) // prefer signaling, if possible 
        || IsFiltered(filterContext)) // filtered? 
        return; 

       LogException(e); 
      } 
     } 
    } 

    private static bool RaiseErrorSignal(Exception e) 
    { 
     HttpContext context = HttpContext.Current; 
     if (context == null) 
      return false; 
     var signal = ErrorSignal.FromContext(context); 
     if (signal == null) 
      return false; 
     signal.Raise(e, context); 
     return true; 
    } 

    private static bool IsFiltered(ExceptionContext context) 
    { 
     var config = context.HttpContext.GetSection("elmah/errorFilter") 
        as ErrorFilterConfiguration; 

     if (config == null) 
      return false; 

     var testContext = new ErrorFilterModule.AssertionHelperContext(
      context.Exception, HttpContext.Current); 

     return config.Assertion.Test(testContext); 
    } 

    private static void LogException(Exception e) 
    { 
     HttpContext context = HttpContext.Current; 
     ErrorLog.GetDefault(context).Log(new Error(e, context)); 
    } 
}