Sanjay Uttam

November 2009 Entries

Error Handling in ASP.NET MVC 1 [Part 2 of 2]

In the first post in this series, I provided a little info on the HandleError attribute in MVC 1.  In case you don’t want to flip back, the HandleError attribute can decorate a method or a class and will push your users to a generic errors view provided customErrors is “On” or “RemoteOnly”.  There’s a little more to it, but that’s all the background we need for this post.

The out-of-the-box HandleError attribute works well, until you’re in a scenario where you need to do more than hide your errors.  Typically, you may want to do some logging or fire-off some alerts.  Now, as luck should have it, I did some searching before writing this up and Danny Tuppeny already has a great post on this very subject…I encourage you to take a peak at his post, as I’ve provided a very high-level, yet functional summary below.

The facts are these…

- System.Web.Mvc.Controller contains an OnException method that gets fired when an exception occurs [provided custom errors are On/RemoteOnly in the web.config]

- The OnException method can easily be overridden, allowing you to either completely change behavior or add behavior (by calling base.OnException)

- This method will fire regardless of whether your class or method is decorated with HandleError

This means that your could will look like this:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Web;
   5: using System.Web.Mvc;
   6:  
   7: namespace MvcErrorHandling.Controllers
   8: {
   9:     public class ControllerBase : System.Web.Mvc.Controller
  10:     {
  11:         protected override void OnException(ExceptionContext filterContext)
  12:         {
  13:             //Do whatever stuff you'd like
  14:             DoSomeOtherStuff();
  15:             
  16:             //Displays a friendly error, doesn't require HandleError
  17:             filterContext.ExceptionHandled = true;
  18:             this.View("Error").ExecuteResult(this.ControllerContext);
  19:             
  20:             //Displays a friendly error, *requires* HandlError
  21:             //base.OnException(filterContext);
  22:         }
  23:  
  24:         protected void DoSomeOtherStuff() { /* brevity */ }
  25:     }
  26: }

To get the above code to work you’d simply make your controller inherit from ControllerBase.  Of course, you’d likely have additional utility-methods in this class that you’d need in multiple controllers. 

Lines 17 and 18 can be used to push the user to your error view after you execute the DoSomeOtherStuff() method – this would not require the HandleError attribute.  Alternatively, you can execute System.Web.Mvc.Controller’s OnException by calling it explicitly as it’s done on line 21.  In this case, the HandleError would be required to push your use down the custom-error path you’ve got configured. 

And that’s pretty much all there is to centralizing & customizing your error-handling in MVC 1.  

kick it on DotNetKicks.com

Share this post :

Technorati Tags: ,

Error Handling in ASP.NET MVC 1 [Part 1 of 2]

I’ve been using ASP.NET MVC Release 1 for a bit now, and while it’s definitely not for every application, I happen to like it quite a bit.  There has been a lot of activity on MS-centric blogs regarding MVC, but there are still some really mundane tasks that there could be more information on.  So, this series of posts isn’t going to be anything crazy; it will, however, illustrate what options you have to do centralized error-handling using MVC 1.

We’ll start at the beginning…

The System.Web.Mvc.dll comes with the HandleErrorAttribute class, which contains..wait for it…the HandleError attribute.   This information won’t be important until later in this series, but the HandleErrorAttribute class inherits from the FilterAttribute class, and implements the IExceptionFilter interface – the interface requires a method with the following signature. 

public virtual void OnException(ExceptionContext filterContext);

This method is really where the brunt of the work is done when you use the provided [HandleError] attribute.  In case you’ve never taken a look using Reflector, this HandleErrorAttribute’s implementation of OnException looks like this:

public virtual void OnException(ExceptionContext filterContext)
  {
      if (filterContext == null)
      {
          throw new ArgumentNullException("filterContext");
      }
      if (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled)
      {
          Exception innerException = filterContext.Exception;
          if ((new HttpException(null, innerException).GetHttpCode() == 500) && this.ExceptionType.IsInstanceOfType(innerException))
          {
              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();
              result.ViewName = this.View;
              result.MasterName = this.Master;
              result.ViewData = new ViewDataDictionary<HandleErrorInfo>(model);
              result.TempData = filterContext.Controller.TempData;
              filterContext.Result = result;
              filterContext.ExceptionHandled = true;
              filterContext.HttpContext.Response.Clear();
              filterContext.HttpContext.Response.StatusCode = 500;
              filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
          }
      }
  }

Essentially, you’re grabbing some information from the ExceptionContext, and you’re using the HandleErrorInfo class to pass this information back to your view.

Using [HandleError] is really as easy as using any other attribute.  You simply decorate your method or class with the attribute and your errors will be pushed to the default view for errors (Views/Shared/Error.aspx)

Sample usage of [HandleError]:

namespace MvcErrorHandling.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            if (true)
            { 
                throw new ApplicationException("Some error...");
            }
            return View();
        }
        //removed...

Alternatively, you can provide the HandleError attribute with some arguments to specify a view other than the default error-view, or specify a specific view based on the exception type.  Here’s an example of the usage for that…

[HandleError(ExceptionType = typeof(ApplicationException), View = "AppErrorPage")]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        if (true)
        { 
            throw new ApplicationException("Some error...");
        }
        return View();
    }
    //removed...

The only other thing you’ll want to make sure you do is ensure your web.config <customErrors> section is configured appropriately.  That is, you’ll want to make sure customErrors mode=”On” to test this out.

Hope this helps somebody; the next part in this series will demonstrate how to add functionality to the existing OnException method that the HandleErrorAttribute class implements, such as logging.

kick it on DotNetKicks.com

Share this post :

Technorati Tags: ,