I'm writting an ASP.NET MVC app and I encountered following problem. I want to make custom error pages with detailed information about the errors (such as error message or what controller caused the error), but I can't provide the model on the view with an HandleErrorInfo object.
At first I configured the Web.config file to handle custom errors:
<customErrors mode="On" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/NotFound"/>
</customErrors>
Then I created the Error Controller to manage the error views:
public class ErrorController : Controller
{
public ActionResult Index()
{
return View("Error");
}
public ViewResult NotFound()
{
Response.StatusCode = 404;
return View("NotFound");
}
}
And on the View I added the model type:
@model System.Web.Mvc.HandleErrorInfo
But the model is null everytime and I don't know how to pass the right object with error details to the view and where this object should be created. Can you help me? Is it even possible to do it this way?
So you're dealing with two different 'layers' here. <customErrors>
is apart of the main ASP.NET framework. Then HandleError
is apart of the MVC framework. When you use <customErrors>
ASP.NET is unaware of how to pass the exception information into a view, it'll just load/redirect you to the error page.
To make the view work, you need to keep everything inside the MVC ecosystem. So you'll need to use HandleErrorAttribute
, or a varient . You can see in the source code of the attribute it attempts to detect when an unhandled exception has happened, and if custom errors are enabled, then spins up a new ViewResult
with an instance of HandleErrorInfo
that has the exception information inside of it.
To be noted, in a default MVC project, HandleErrorAttribute
is applied as a global filter inside of the App_Start/FilterConfig.cs
file.
I found another way. Sending error model to view from controller.
1. Global.asax
protected void Application_Error(object sender, EventArgs e)
{
var httpContext = ((MvcApplication)sender).Context;
var currentController = " ";
var currentAction = " ";
var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
if (currentRouteData != null)
{
if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
{
currentController = currentRouteData.Values["controller"].ToString();
}
if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
{
currentAction = currentRouteData.Values["action"].ToString();
}
}
var ex = Server.GetLastError();
//var controller = new ErrorController();
var routeData = new RouteData();
var action = "GenericError";
if (ex is HttpException)
{
var httpEx = ex as HttpException;
switch (httpEx.GetHttpCode())
{
case 404:
action = "NotFound";
break;
// others if any
}
}
httpContext.ClearError();
httpContext.Response.Clear();
httpContext.Response.StatusCode = ex is HttpException ? ((HttpException)ex).GetHttpCode() : 500;
httpContext.Response.TrySkipIisCustomErrors = true;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = action;
routeData.Values["exception"] = new HandleErrorInfo(ex, currentController, currentAction);
IController errormanagerController = new ErrorController();
HttpContextWrapper wrapper = new HttpContextWrapper(httpContext);
var rc = new RequestContext(wrapper, routeData);
errormanagerController.Execute(rc);
}
2. Error Controller:
public class ErrorController : Controller
{
//
// GET: /Error/
public ActionResult Index()
{
return RedirectToAction("GenericError", new HandleErrorInfo(new HttpException(403, "Dont allow access the error pages"), "ErrorController", "Index"));
}
public ViewResult GenericError(HandleErrorInfo exception)
{
return View("Error", exception);
}
public ViewResult NotFound(HandleErrorInfo exception)
{
ViewBag.Title = "Page Not Found";
return View("Error", exception);
}
}
3. View/Shared/Error.cshtml:
@model System.Web.Mvc.HandleErrorInfo
@{
ViewBag.Title = ViewBag.Title ?? "Internal Server Error";
}
<div class="list-header clearfix">
<span>Error : @ViewBag.Title</span>
</div>
<div class="list-sfs-holder">
<div class="alert alert-error">
An unexpected error has occurred. Please contact the system administrator.
</div>
@if (Model != null && HttpContext.Current.IsDebuggingEnabled)
{
<div>
<p>
<b>Exception:</b> @Model.Exception.Message<br />
<b>Controller:</b> @Model.ControllerName<br />
<b>Action:</b> @Model.ActionName
</p>
<div style="overflow: scroll">
<pre>
@Model.Exception.StackTrace
</pre>
</div>
</div>
}
</div>
4. web.config:
<system.web>
<customErrors mode="Off" />
</system.web>
Credits: https://thatsimpleidea.wordpress.com/2013/10/28/mvc-error-page-implementation/#comment-166
This didn't work for me but inspired me to find that my Global.asax.Application_Start()
didn't register the FilterConfig
class like so:
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
This, coupled with Steven V's answer resolved my null Model issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With