I want a custom error page shown for 500, 404 and 403. Here\'s what I have done:
Enabled custom errors in the web.config as follows:
Here is my solution. Use [ExportModelStateToTempData] / [ImportModelStateFromTempData] is uncomfortable in my opinion.
~/Views/Home/Error.cshtml:
@{
ViewBag.Title = "Error";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Error</h2>
<hr/>
<div style="min-height: 400px;">
@Html.ValidationMessage("Error")
<br />
<br />
<button onclick="Error_goBack()" class="k-button">Go Back</button>
<script>
function Error_goBack() {
window.history.back()
}
</script>
</div>
~/Controllers/HomeController.sc:
public class HomeController : BaseController
{
public ActionResult Index()
{
return View();
}
public ActionResult Error()
{
return this.View();
}
...
}
~/Controllers/BaseController.sc:
public class BaseController : Controller
{
public BaseController() { }
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is ViewResult)
{
if (filterContext.Controller.TempData.ContainsKey("Error"))
{
var modelState = filterContext.Controller.TempData["Error"] as ModelState;
filterContext.Controller.ViewData.ModelState.Merge(new ModelStateDictionary() { new KeyValuePair<string, ModelState>("Error", modelState) });
filterContext.Controller.TempData.Remove("Error");
}
}
if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
{
if (filterContext.Controller.ViewData.ModelState.ContainsKey("Error"))
{
filterContext.Controller.TempData["Error"] = filterContext.Controller.ViewData.ModelState["Error"];
}
}
base.OnActionExecuted(filterContext);
}
}
~/Controllers/MyController.sc:
public class MyController : BaseController
{
public ActionResult Index()
{
return View();
}
public ActionResult Details(int id)
{
if (id != 5)
{
ModelState.AddModelError("Error", "Specified row does not exist.");
return RedirectToAction("Error", "Home");
}
else
{
return View("Specified row exists.");
}
}
}
I wish you successful projects ;-)
I would Recommend to use Global.asax.cs File.
protected void Application_Error(Object sender, EventArgs e)
{
var exception = Server.GetLastError();
if (exception is HttpUnhandledException)
{
Server.Transfer("~/Error.aspx");
}
if (exception != null)
{
Server.Transfer("~/Error.aspx");
}
try
{
// This is to stop a problem where we were seeing "gibberish" in the
// chrome and firefox browsers
HttpApplication app = sender as HttpApplication;
app.Response.Filter = null;
}
catch
{
}
}
There seem to be a number of steps here jumbled together. I'll put forward what I did from scratch.
Create the ErrorPage
controller
public class ErrorPageController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Oops(int id)
{
Response.StatusCode = id;
return View();
}
}
Add views for these two actions (right click -> Add View). These should appear in a folder called ErrorPage.
Inside App_Start
open up FilterConfig.cs
and comment out the error handling filter.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// Remove this filter because we want to handle errors ourselves via the ErrorPage controller
//filters.Add(new HandleErrorAttribute());
}
Inside web.config add the following <customerErrors>
entries, under System.Web
<customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
<error redirect="~/ErrorPage/Oops/404" statusCode="404" />
<error redirect="~/ErrorPage/Oops/500" statusCode="500" />
</customErrors>
Test (of course). Throw an unhandled exception in your code and see it go to the page with id 500, and then use a URL to a page that does not exist to see 404.
It seems i came late to the party, but you should better check this out too.
So in system.web
for caching up exceptions within the application such as return HttpNotFound()
<system.web>
<customErrors mode="RemoteOnly">
<error statusCode="404" redirect="/page-not-found" />
<error statusCode="500" redirect="/internal-server-error" />
</customErrors>
</system.web>
and in system.webServer
for catching up errors that were caught by IIS and did not made their way to the asp.net framework
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly">
<remove statusCode="404"/>
<error statusCode="404" path="/page-not-found" responseMode="Redirect"/>
<remove statusCode="500"/>
<error statusCode="500" path="/internal-server-error" responseMode="Redirect"/>
</system.webServer>
In the last one if you worry about the client response then change the responseMode="Redirect"
to responseMode="File"
and serve a static html file, since this one will display a friendly page with an 200 response code.
In web.config add this under system.webserver tag as below,
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<remove statusCode="500"/>
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound"/>
<error statusCode="500" responseMode="ExecuteURL"path="/Error/ErrorPage"/>
</httpErrors>
and add a controller as,
public class ErrorController : Controller
{
//
// GET: /Error/
[GET("/Error/NotFound")]
public ActionResult NotFound()
{
Response.StatusCode = 404;
return View();
}
[GET("/Error/ErrorPage")]
public ActionResult ErrorPage()
{
Response.StatusCode = 500;
return View();
}
}
and add their respected views, this will work definitely I guess for all.
This solution I found it from: Neptune Century
My current setup (on MVC3, but I think it still applies) relies on having an ErrorController
, so I use:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error">
<error redirect="~/Error/NotFound" statusCode="404" />
</customErrors>
</system.web>
And the controller contains the following:
public class ErrorController : Controller
{
public ViewResult Index()
{
return View("Error");
}
public ViewResult NotFound()
{
Response.StatusCode = 404; //you may want to set this to 200
return View("NotFound");
}
}
And the views just the way you implement them. I tend to add a bit of logic though, to show the stack trace and error information if the application is in debug mode. So Error.cshtml looks something like this:
@model System.Web.Mvc.HandleErrorInfo
@{
Layout = "_Layout.cshtml";
ViewBag.Title = "Error";
}
<div class="list-header clearfix">
<span>Error</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>