I’ve got a catchall in my base controller that handles errors I don’t catch. It goes roughly like this:
protected override void OnException(ExceptionContext filterContext)
{
// Bail if we can't do anything
if (filterContext == null)
return;
// log
var ex = filterContext.Exception ??
new Exception("No further information exists.");
LogException(ex);
filterContext.ExceptionHandled = true;
var data = new ErrorPresentation
{
ErrorMessage = HttpUtility.HtmlEncode(ex.Message),
TheException = ex
};
filterContext.Result = View("Error", data);
base.OnException(filterContext);
}
Now this works great if the error happens in the controller. The issue is that if the error is during the aspx page rendering (say, in an HtmlHelper method), the whole error view gets rendered, in place on the page where the error occurred. That means that the entire error page (MasterPage and all) gets rendered within the page that’s errored. Not exactly the expected behavior.
I’ve tried changing View to a RedirectToAction, but that won’t work as a route doesn’t exist for every controller (Home/Error, Configuration/Error, etc).
How can I get this to work for both errors in the controller AND errors on the page?
You would need a way to track what state the page is in so that you can differentiate whether you are executing the action — in which case you want to replace the result — or executing the result — in which case you want to discard the contents of the response and execute a new ViewResult for the error. Keeping a flag in the base controller would be one way of handling this. You might also be able to tell based on the exception type. I’m not sure how reliable that would be.
Once you figure out the state you can do:
Comment: Generally I don’t advocate doing this. I think that your controller action should guarantee to the View that all of the data that it needs is there or your View should be written defensively to ensure that no exceptions (particularly NullReferenceExceptions) don’t happen.