2012-01-24 9 views
5

He comenzado un proyecto de plantilla MVC 3 en VS10 y modificados global.asax.cs como tal:HandleErrorAttribute no trabajar

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 }); 
} 

Para web.config añadí:

<customErrors mode="On"> 

Luego creó el puntos de vista correspondientes y finalmente agregó un DivideByZero-throw a una de las acciones.

El resultado: se muestra la vista AllOtherExceptions.

Respuesta

21

Aunque odio no estar de acuerdo con nada de lo que dice Darin, él está equivocado en este caso.

No hay problema con la configuración de las propiedades (esa es la forma en que se se supone para hacerlo).

La única razón por la que su código original no funcionó como se esperaba es porque tiene el conjunto Order incorrecto.

Ver MSDN:

El OnActionExecuting (ActionExecutingContext), OnResultExecuting (ResultExecutingContext), y OnAuthorization (AuthorizationContext) Filtros ejecutan en orden hacia adelante. Los filtros OnActionExecuted (ActionExecutedContext), OnResultExecuting (ResultExecutingContext) y OnException (ExceptionContext) se ejecutan en orden inverso.

Así que su filtro genérico AllOtherExceptions es necesario que haya el menor número Order, no el más alto.

Espero que eso ayude para la próxima vez.

+0

Parece que tienes un caso, ¡miedo! Como Darin resolvió mi problema, tendrás que pelear con los votos por arriba. – Martin

+0

¡Gracias por esto, debería ser la respuesta! –

+0

Cambió la respuesta ... – Martin

8

No debe establecer propiedades al registrar un filtro de acción global. Se puede escribir un filtro de error de identificador personalizado:

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; 
      } 
     } 
    } 
} 

y luego registrarlo:

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

Funcionó por supuesto. ¿Cómo es que no puedes establecer propiedades cuando registras un filtro de acción global? – Martin

0

hacer Compruebe la respuesta de miedo a continuación. Sin duda, es más simple, si funciona.

Dado que se produjo después de algunas semanas, así es como finalmente se deleturó mi filtro, utilizando la respuesta de Darins e incorporando Elmah-reporting, con el código del tema this.

Todavía no sé por qué no puede establecer propiedades en un filtro de acción global.

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)); 
    } 
}