Question

I want to create a custom error page for my MVC4 project with my own model.

I used the approach from Darin Dimitrov from Custom error pages on asp.net MVC3

Now i wanted to use my own (test)model:

public class ErrorModel
{
    public string message { get; set; }
}

Now when I use customErrors mode="Off" everything works fine but only on the local machine. When I access the machine from a remote machine however the default error is shown. (which is the intended way - i guess)

Now when i set the System suddenly expects his own model instead of mine:

"The model item passed into the dictionary is of type 'System.Web.Mvc.HandleErrorInfo', but this dictionary requires a model item of type 'Project.Controllers.ErrorModel'.

How can i either force the system to show the page through customErrors="Off" to the remote system when the mode is Off or how to force him to use my model instead of the HandleErrorInfo model?

My ErrorController

public class ErrorController : Controller
{
  public ActionResult General(Exception exception)
  {
      var viewModel = new ErrorModel()
      {
          message = exception.Message          
      };
      return View(viewModel);
}

The View:

@model SRMv2.WebUI.Controllers.ErrorModel
@{
}
@Html.Raw(Model.message)

And in the Global.asax

protected void Application_Error()
{
    HttpContext.Current.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
    HttpContext.Current.Response.Cache.SetValidUntilExpires(false);          HttpContext.Current.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    HttpContext.Current.Response.Cache.SetNoStore();

    var exception = Server.GetLastError();
    var httpException = exception as HttpException;
    Response.Clear();
    Server.ClearError();
    var routeData = new RouteData();
    routeData.Values["controller"] = "Errors";
    routeData.Values["action"] = "General";
    routeData.Values["exception"] = exception;
    Response.StatusCode = 500;
    if (httpException != null)
    {
       Response.StatusCode = httpException.GetHttpCode();
       switch (Response.StatusCode)
       {
          case 403:
            routeData.Values["action"] = "Http403";
            break;
          case 404:
            routeData.Values["action"] = "Http404";
            break;
        }
     }

   IController errorController = new ErrorController();
   var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
   errorController.Execute(rc);
}
Was it helpful?

Solution

What is happening is that your error-handling code is throwing an unhandled exception, which is then caught by the default aspnet handler. W/o actually seeing the view you're using to render the error page, I am assuming that you didn't change the model type in there to match the model set in your controller.

OTHER TIPS

maf748 you were completely right about your answer. The interesting part is why it happened.

When the customError is Off the MVC framework calls Application_Error() in the global.asax were ErrorController is called (see Question). When you switch customError to On the MVC framework says, fine the user deals with the Exception, finds the View and renders it, without the ErrorController properly being called. So he couldn't render the viewmodel and the default viewModel (System.Web.Mvc.HandleErrorInfo) was used.

So the views didn't match, the framework raised the Application_Error() and Server.GetLastError() returned that the viewmodels didn't match... which is correct and then the ErrorController/View is generated with this error...

So my solution?

Call the ErrorController OnActionExecuted()

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {

        if (filterContext.Exception != null)
        {
            filterContext.ExceptionHandled = true;
            IController errorController = new ErrorController();
            var routeData = new RouteData();
            routeData.Values["controller"] = "Errors";
            routeData.Values["action"] = "General";
            routeData.Values["exception"] = filterContext.Exception;

            var rc = new RequestContext(filterContext.HttpContext, routeData);
            errorController.Execute(rc);
        }

Thanks again for setting me on the right track as most of the stuff described is hidden behind the framework.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top