Sunday, October 4, 2015

Custom Error Page in ASP.NET MVC

Setting up custom error page for 400 (bad request), 401 (unauthorized), 403 (forbidden), 404 (not found), 500 (internal server error) seemed like a web.config task as simple as specifying
    
<system.web>
    <customErrors mode="On" redirectMode="ResponseRedirect"  >
      <error statusCode="400" redirect="~/CustomError/BadRequest"/>
      <error statusCode="401" redirect="~/CustomError/Unauthorized" />
      <error statusCode="404" redirect="~/CustomError/NotFound"  />
      <error statusCode="403" redirect="~/CustomError/Forbidden"/>
      <error statusCode="500" redirect="~/CustomError/InternalServerError"/>
    </customErrors>
</system.web>
However, the above may not allow our custom error pages to handle certain cases.

For example, the default IIS 404 error page, not my custom error page, will handle 404 for url that is not understood by my MVC application's routing rule (i.e., http://localhost/MyApp/a/b/c/d/e/f).

It may be easier to use <httpErrors> under <system.webServer> rather than <customErrors> in <system .web>. The above can be converted to below. Note that we cannot use ~/ in the path attribute. <system.webServer> is IIS-level override for customError handling in this case. So remove the above and try something like the following.

<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">      
    <remove statusCode="400" />
    <remove statusCode="401" />
    <remove statusCode="403" />
    <remove statusCode="404" />
    <remove statusCode="500" />
    <error statusCode="400" path="/MyApp/CustomError/BadRequest" responseMode="ExecuteURL"/>
    <error statusCode="401" path="/MyApp/CustomError/Unauthorized" responseMode="ExecuteURL"/>
    <error statusCode="403" path="/MyApp/CustomError/Forbidden" responseMode="ExecuteURL"/> 
    <error statusCode="404" path="/MyApp/CustomError/NotFound" responseMode="ExecuteURL"/>
    <error statusCode="500" path="/MyApp/CustomError/InternalServerError" responseMode="ExecuteURL"/>
  </httpErrors>
</system.webServer>


Below is the Controller


public class CustomErrorController : Controller
{
 public ActionResult BadRequest()
 {
  Response.StatusCode = 400;
  ViewBag.ErrorCode = "400";
  ViewBag.ErrorTitle = "400 Error - Bad Request";
  ViewBag.ErrorMessage = 
   "The resource you tried to access appears to be incomplete.\n" + 
   "Please check your URL and try again.";
  return View("Error");
 }
 public ActionResult Unauthorized()
 {
  Response.StatusCode = 401;
  ViewBag.ErrorCode = "401";
  ViewBag.ErrorTitle = "401 Error - Unauthorized";
  ViewBag.ErrorMessage = 
   "The resource you tried to access appears to require a user permission.\n" + 
   "Please re-launch the browser and try again.";
  return View("Error");
 }
 public ActionResult Forbidden()
 {
  Response.StatusCode = 403;
  ViewBag.ErrorCode = "403";
  ViewBag.ErrorTitle = "403 Error - Forbidden: Access is denied";
  ViewBag.ErrorMessage = 
   "The resource you tried to access is not allowed. \n" + 
   "Please check your URL and try again.";
  return View("Error");
 }
 public ActionResult NotFound()
 {
  Response.StatusCode = 404;
  ViewBag.ErrorCode = "404";
  ViewBag.ErrorTitle = "404 Error - Resource Not Found";
  ViewBag.ErrorMessage = 
   "The resource you tried to access was not found.\n" + 
   "Please check your URL and try again.";
  return View("Error");
 }
 public ActionResult InternalServerError()
 {
  Response.StatusCode = 500;
  ViewBag.ErrorCode = "500";
  ViewBag.ErrorTitle = "500 Error - Internal Server Error";
  ViewBag.ErrorMessage = 
   "An error occurred while system tried to process your request.\n" + 
   "Try again, and if problem persists contact system administrator.";
  return View("Error");
 }
}


And the View

@{
    ViewBag.Title = ViewBag.Title;
}

<div style="text-align: center;">
    <div style="font-size: 10em; color:#ccc; font-weight: bold; ">
        @ViewBag.ErrorCode
    </div>

    <h2>
        @ViewBag.ErrorTitle
    </h2>

    <h3 style="white-space: pre-wrap; word-wrap: break-word;">@ViewBag.ErrorMessage</h3>

    <h4>
        <a href="javascript:void(0);" onclick="javascript: history.go(-1);">Back</a>
    </h4>
</div>


And this is the custom 404 page.


No comments: