Wednesday, June 13, 2012

ASP.Net MVC Error Handling at Method, Controller and Global Levels


Traditional Asp.Net supports
  • Custom error redirect in web.config 
  • Application_Error in Global.asax
On top of that MVC3 introduced 
How do you put these pieces together to build a more robust MVC site?

1. Handle controller/method level MVC errors with HandleErrorAttribute
You can decorate your controllers or action methods with HandleErrorAttribute.

    [HandleError]
    public class MyController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    }
Or
    public class MyController : Controller
    {
        [HandleError]
        public ActionResult Index()
        {
            return View();
        }
    }

When an action method in the controller with HandleError attribute decoration throws an exception and it is not handled by your code, MVC displays the Error view that is located in the ~/Views/Shared folder. It's worth to note that HandleErrorAttribute renders the view without passing through any error handling controller you may have.  Yes this is somewhat confusing.  I first learned this from Tom Dupont's blog and later confirmed with simulating an exception and stepping through the code.

You may override HandleErrorAttribute's default behavior by specifying the exception types that should be handled, the name of the view to render, the order in which the filters are applied if you have more than one HandleErrorAttribute for your controller/method.  See MSDN for more details.

If you want to enable error handling for all of your controllers yet don't like the tedious work of decorating your controllers one-by-one, you can register global HandleErrorAttribute in Global.asax.  This is enabled by default in MVC3.

        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }

2. Log errors by overriding HandleErrorAttribute.OnException or Controller.OnException
By now you may wonder how/where I can log errors.  HandleErrorAttribute renders an error view to users, but doesn't log errors for you automatically.  This is where OnException method comes into play.  Both HandleErrorAttribute and Controller classes have OnException method that can be overridden for error logging.  

In Controller's case, first you override the OnException method and add your own logic for error logging or notification.

    public class BaseController : Controller
    {
        protected override void OnException(ExceptionContext filterContext)
        {
            // Do additional things like logging or emailing here.

            base.OnException(filterContext);
        }
    }

Then you inherit your controllers from the new BaseController instead of the default Controller class.

    public class HomeController : BaseController
    {
        public ActionResult Index()
        {
            // Do something here

            return View();
        }
    }

From that point on, your OnException will be called whenever an unhandled exception is thrown in your controller methods.
  
3. Handle non-MVC errors at global level with Application_Error
HandleErrorAttribute and Controller.OnException deal with application or server errors, but not errors outside of MVC pipeline such as 404 Not Found error.  Those non-MVC errors should be handled/logged in your Application_Error method in Global.asax.

If you neither register global HandleErrorAttribute nor decorate your controller/method with HandleErrorAttribute, exceptions will bubble up to Application_Error.

4. Display custom errors to the end users.
If you already registered global HandleErrorAttribute or decorated your methods/controllers with the same attribute but still saw the Yellow Screen of Death (YOSD) with potentially security-compromising error details like stack trace, you should check customErrors element in your web.config to make sure the mode attribute is set to either RemoteOnly (by default) or On.

    <customErrors mode="RemoteOnly" defaultRedirect="/Error/HttpError">
      <error statusCode="404" redirect="/Error/Http404"/>
    </customErrors>

Other Resources


3 comments:

  1. Nice information...Thanks Its Helpful.

    ReplyDelete
  2. This is awesome!! really helpful for me. Thanks for sharing with us. Following links also helped me to complete my task.

    http://www.mindstick.com/Articles/3b3db6b5-a464-4ca6-9d77-8b89e824054c/?Exception%20Handling%20in%20ASP%20NET%20MVC3

    http://www.codeproject.com/Articles/422572/Exception-Handling-in-ASP-NET-MVC

    ReplyDelete
  3. control 404 error on blogger
    Insted of 404 error on Blogger
    http://allinworld99.blogspot.com/2014/04/seo-optimization-for-blogger.html

    ReplyDelete