views:

183

answers:

1

In my Site.Master file, I have 3 simple ViewData parameters (the only 3 in my entire solution). These ViewData values are critical for every single page in my application. Since these values are used in my Site.Master, I created an abstract SiteController class that overrides the OnActionExecuting method to fill these values for every Action method on every controller in my solution.

[HandleError(ExceptionType=typeof(MyException), View="MyErrorView")]
public abstract class SiteController : Controller
{
  protected override void OnActionExecuting(...)
  {
    ViewData["Theme"] = "BlueTheme";
    ViewData["SiteName"] = "Company XYZ Web Portal";
    ViewData["HeaderMessage"] = "Some message...";        

    base.OnActionExecuting(filterContext);

  }
}

The problem that I'm faced with is that these values are not being passed to MyErrorView (and ultimately Site.Master) when the HandleErrorAttribute kicks in from the SiteController class level attribute. Here is a simple scenario to show my problem:

public class TestingController : SiteController
{
  public ActionResult DoSomething()
  {
    throw new MyException("pwnd!");
  }
}

I've tried filling the ViewData parameters by overriding the OnException() method in my SiteController as well, but to no avail. :(

What is the best way to pass the ViewData parameters to my Site.Master in this case?

+2  A: 

This is because HandleErrorAttribute change the ViewData passed to the view when error occurs. It passes instance of HandleErrorInfo class with information about Exception, Controller and Action.

What you can do is replace this attribute by the the one implemented below:

public class MyHandleErrorAttribute : HandleErrorAttribute {

 public override 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"];
    // Preserve old ViewData here
    var viewData = new ViewDataDictionary<HandleErrorInfo>(filterContext.Controller.ViewData), 
    // Set the Exception information model here
    viewData.Model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
    filterContext.Result = new ViewResult { ViewName = this.View, MasterName = this.Master, ViewData = viewData, TempData = filterContext.Controller.TempData };
    filterContext.ExceptionHandled = true;
    filterContext.HttpContext.Response.Clear();
    filterContext.HttpContext.Response.StatusCode = 500;
    filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
   }
  }
 }
}
Dmytrii Nagirniak
Wow, this was a lot more complex than I thought it would be. :) I've looked through it to understand it and it makes perfect sense what your doing and why you're doing it. Thanks for your answer!
Luc