1

I'm using ASP.MVC 4. I have a strongly typed layout which is connected to a base view model (every other view model is inheriting from the base view model). I'm trying to handle errors using a standard HandleError filter. It's out of box configured and works if layout isn't strongly typed.

My example exception is following:

public class TestController : Controller
{
    public ActionResult Index()
    {
        throw new Exception("oops");
    }
}

When the mechanism tries to plug Error page into strongly typed layout it gets in trouble because there's no model for it.

Does anyone know what is a scenario for using strongly typed layouts with the HandleError filter? Is there any possibility to set model for the layout before the exception is thrown?

EDIT:

Possible solution is turning off standard error handling mechanism and catching exceptions in the Application_Error method in the Global.asax. Example solution you can find here: ASP.MVC HandleError attribute doesn't work

Anyway - if someone have another solution, please post it.

Community
  • 1
  • 1
Arkadiusz Kałkus
  • 17,101
  • 19
  • 69
  • 108

3 Answers3

4

You could write your own HandleError attribute and register it on FilterConfig instead of the default one. Your custom one will extend the default attribute, overriding the result so the model instance passed into the view is of the required type:

public class CustomHandleErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext context)
    {
        //When already handled, do nothing
        if (context.ExceptionHandled)
            return;

        //Run the base functionality
        base.OnException(context);

        //If the base functionality didnt handle the exception, then exit (as the exception is not of the type this filter should handle)
        if (!context.ExceptionHandled) return;

        //Set a view as the result           
        context.Result = GetViewResult(context);            
    }

    private ViewResult GetViewResult(ExceptionContext context)
    {
        //The model of the error view (YourModelType) will inherit from the base view model required in the layout
        YourModelType model = new YourModelType(context.Exception, ...);
        var result = new ViewResult
        {
            ViewName = View,
            ViewData = new ViewDataDictionary<YourModelType>(model),
            TempData = context.Controller.TempData
        };
        return result;
    }
}

Then register globally this filter instead of the default HandleErrorAttribute:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new CustomHandleErrorAttribute());
    ...
}
Daniel J.G.
  • 34,266
  • 9
  • 112
  • 112
1

Only way I can think of is

  • a) In Global.asax.cs, handle Application_Error (or Application_OnError, the signature escapes me now) and redirect to a strongly typed view
  • b) Edit web.config customErrors section to point to your strongly typed view. However, doing b) can be flakey as other have found e.g. benfoster.io/blog/aspnet-mvc-custom-error-pages
Jason Evans
  • 28,906
  • 14
  • 90
  • 154
0

You can get the controller name and the action name that reproduce the error by doing so:

public class CustomErrorException: HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        filterContext.Result = new ViewResult {
            ViewName = "CustomError",
            ViewData = new ViewDataDictionary<HandleErrorInfo> { 
                Model = new HandleErrorInfo(
                    exception: filterContext.Exception,
                    controllerName: filterContext.RequestContext.RouteData.Values["controller"].ToString(),
                    actionName: filterContext.RequestContext.RouteData.Values["action"].ToString()
                ) 
            }
        };

        //You can log your errors here.
        filterContext.ExceptionHandled = true;
    }
}

in the "CustomError.cshtml" view you can do this:
@model HandleErrorInfo
Hey this is a custom error!!!
Controller name: @Model.ControllerName
action name: @Model.ActionName
Exception message: @Model.Exception.Message

Mina Luke
  • 2,056
  • 1
  • 20
  • 22