views:

857

answers:

4

I'm trying to get my head around the Error Handling in MVC. What I'm looking for is a centralized way to catch errors, log them, if possible resolve them, if nessecary take other actions and finally show the correct view to the user.

I think I can use the [HandleError] filter for this, but I don't see any way to route it to a Controller/Action. The only option I see is pointing it directly to a view.

+1  A: 

Why not create your own ErrorResult deriving from ActionResult?

leppie
+1  A: 

HandleErrorAttribute that comes with MVC is a pretty basic IExceptionFilter.

You have a few options to achieve what i think u want.

You can either use [HandleError (Type=typeof(MyException),View="ErrorView")] on actions/controllers or implement your own

HandleErrorAttribute isnt very complex. I think MS recommends you copy this code and modify to suit your requirements.

The OnException override gives you access to all that info you may need - controller, action, route data, etc - through ExceptionContext.

Remember to set the ExceptionHandled. Then you can set the filterContext.Result to a new RedirectToAction instance which redirect to your ErrorController and action - obviously you can expose the specific controller and action with properties.

CVertex
The standard HandleError doesn't allow me to route to a controller I think. So that's not what I need.I think I'll have to roll my own then.Don't happen to have any good material to reference here?
borisCallens
Yup, http://haacked.com/archive/2008/08/14/aspnetmvc-filters.aspx
CVertex
Jep, noticed the links in your reply a tad late :P Thanks.I'm creating a RerouteFilterAttribute now. Got quite some trial/error going on now, but I'll get there.
borisCallens
A: 

What I'm doing (which may or may not be a good practice) is this:

When an error occurs:

  • If I expected it and can handle it, I do (logging it with ELMAH)
  • If I expected it and can't handle it, I log it to ELMAH and return a ViewResult that is my error page
    • Include a description of the error, a standard message and a link back to what I was doing
  • If I didn't expect it, my override of OnError in my base controller class does the previous step
  • All other errors that can't be handled are automatically logged by ELMAH and the request yellowscreens

Most of my generic error handling goes in the base class for all my controllers. The only issue is that I have to manually set a controller and action value in the base class so that it can generate an ActionLink for the redirect in the error page.

Will
Filters seem to be the way to go for error handling instead of overriding onerror. They're nicely orthogonal to controllers.
CVertex
Appreciate the feedback, but I would rather not put the error handling in the same class as my base controller.This would render my base class less reusable since the error handling logic usually is different for every site.I'm currently creating a RerouteErrorAttribute filter to do the job.
borisCallens
+1  A: 

Leppi, iIf you want to send to Action Result, you can define Action and Controller to Redirect on Error. It's a good example, but personaly i don´t like no use custom pages or http codes to codes

Here is and example of my IExtenptionFilter. My base controler has a default IExceptionFilter to process all no controlled errors.

[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes",
    Justification = "This attribute is AllowMultiple = true and users might want to override behavior.")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class GenericExceptionHandlerFilter : ActionFilterAttribute, IExceptionFilter
{

    public Type ExceptionType { get; set;}
    public string RedirectToAction { get; set;}
    public string RedirectToController { get; set;}

    protected bool ApplyFilter(ExceptionContext filterContext)
    {
        Type lExceptionType = filterContext.Exception.GetType();
        return (ExceptionType == null ||
                lExceptionType.Equals(ExceptionType));
    }


    #region IExceptionFilter Members
    public void OnException(ExceptionContext filterContext)
    {

        if (ApplyFilter(filterContext))
        {
            IbfControllerLogger.Log(filterContext.Exception);

            filterContext.ExceptionHandled = true;

            #region Calculate Action Controller Error
            RouteValueDictionary lRoutes = new RouteValueDictionary(new
                {
                    action = RedirectToAction,
                    controller = String.IsNullOrEmpty(RedirectToController) ? (string)filterContext.RouteData.Values["controller"] : RedirectToController
                });
            UrlReWriterUtils.UrlReWriter(filterContext.Controller.ViewData, lRoutes);
            #endregion

            filterContext.Controller.TempData[TempDataName.C_TEMPDATA_EXCEPTIONERROR] = filterContext.Exception;
            filterContext.Result = new RedirectToRouteResult(lRoutes);
        }
    }
    #endregion