2011-11-15 7 views
40

sto ereditando il HandleErrorAttribute nella mia applicazione MVC in modo da poter registrare l'errore:ASP.net MVC - Custom HandleError Filtro - Specificare vista in base al tipo di eccezione

public class HandleAndLogErrorAttribute : HandleErrorAttribute 
{ 
    public override void OnException(ExceptionContext filterContext) 
    { 
     base.OnException(filterContext); 

     if(filterContext.Exception != null) 
     { 
      // log here 
     } 
    } 
} 

sto aggiungendo questo come un filtro globale :

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
    filters.Add(new HandleAndLogErrorAttribute()); 
} 

È possibile specificare una vista personalizzata anche per determinati tipi di eccezioni? Per esempio:

if(filterContext.Exception is DivideByZeroException) 
{ 
    // how do i specify that the view should be DivideByZero? 
} 

risposta

68
  1. creare un nuovo filtro che eredita HandleErrorAttribute (o implementa IExceptionFilter direttamente)
  2. registrarlo in global.asax (sostituendo filters.Add(new HandleError());):

Ecco un filtro che ho creato che tenta di trovare una vista per codice di stato HTTP specifico:

public class MyErrorHandler : FilterAttribute, IExceptionFilter 
{ 
    public void OnException(ExceptionContext filterContext) 
    { 
     if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) 
      return; 

     var statusCode = (int) HttpStatusCode.InternalServerError; 
     if (filterContext.Exception is HttpException) 
     { 
      statusCode = filterContext.Exception.As<HttpException>().GetHttpCode(); 
     } 
     else if (filterContext.Exception is UnauthorizedAccessException) 
     { 
      //to prevent login prompt in IIS 
      // which will appear when returning 401. 
      statusCode = (int)HttpStatusCode.Forbidden; 
     } 
     _logger.Error("Uncaught exception", filterContext.Exception); 

     var result = CreateActionResult(filterContext, statusCode); 
     filterContext.Result = result; 

     // Prepare the response code. 
     filterContext.ExceptionHandled = true; 
     filterContext.HttpContext.Response.Clear(); 
     filterContext.HttpContext.Response.StatusCode = statusCode; 
     filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
    } 

    protected virtual ActionResult CreateActionResult(ExceptionContext filterContext, int statusCode) 
    { 
     var ctx = new ControllerContext(filterContext.RequestContext, filterContext.Controller); 
     var statusCodeName = ((HttpStatusCode) statusCode).ToString(); 

     var viewName = SelectFirstView(ctx, 
             "~/Views/Error/{0}.cshtml".FormatWith(statusCodeName), 
             "~/Views/Error/General.cshtml", 
             statusCodeName, 
             "Error"); 

     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), 
         }; 
     result.ViewBag.StatusCode = statusCode; 
     return result; 
    } 

    protected string SelectFirstView(ControllerContext ctx, params string[] viewNames) 
    { 
     return viewNames.First(view => ViewExists(ctx, view)); 
    } 

    protected bool ViewExists(ControllerContext ctx, string name) 
    { 
     var result = ViewEngines.Engines.FindView(ctx, name, null); 
     return result.View != null; 
    } 
} 
+0

Quali codici di stato HTTP gestisce? Avevo l'impressione che 404 non sarebbe mai stato scoperto da un filtro di errore e che è necessario utilizzare per intrappolarli. – Dismissile

+0

tutto ciò che viene generato tramite HttpException. – jgauffin

+0

Bella soluzione: mi piace soprattutto che conservi informazioni sul controller e sull'azione offensivi. Tx! – Jaans

Problemi correlati