
 March 22, 2012 06:56 by 
 Scott
 Scott
In this blog post I will show how to set up custom error pages in ASP.NET MVC 3 applications to create user-friendly error messages instead of the (yellow) IIS default error pages for both “normal” (non-AJAX) requests and jQuery AJAX requests.
 In this showcase we will implement custom error pages to handle the HTTP error codes 404 (“Not Found”) and 500 (“Internal server error”) which I think are the most common errors that could occur in web applications. In a first step we will set up the custom error pages to handle errors occurring in “normal” non-AJAX requests and in a second step we add a little JavaScript jQuery code that handles jQuery AJAX errors. 
 We start with a new (empty) ASP.NET MVC 3 project and activate custom errors in the Web.config by adding the following lines under <system.web>: 
<customErrors  mode="On" defaultRedirect="/Error">
   <error redirect="/Error/NotFound" statusCode="404"/>
   <error redirect="/Error/InternalServerError" statusCode="500"/>
</customErrors> 
 Note: You can set  mode=”Off” to disable custom errors which could be helpful while developing or debugging. Setting mode=”RemoteOnly” activates custom errors only for remote clients, i.e. disables custom errors when accessing via http://localhost/[...]. In this example setting mode=”On” is fine since we want to test our custom errors. You can find more information about the <customErrors> element here.
 In a next step we  remove the following line in Global.asax.cs file:
filters.Add(new HandleErrorAttribute()); 
 and add a new  ErrorController (Controllers/ErrorController.cs):
public  class ErrorController : Controller
{ 
   public ActionResult Index()
   {
     return InternalServerError();
   } 
    public ActionResult NotFound()
   {
     Response.TrySkipIisCustomErrors = true;
     Response.StatusCode = (int)HttpStatusCode.NotFound;
     return View("NotFound");
   } 
    public ActionResult InternalServerError()
   {
     Response.TrySkipIisCustomErrors = true;
     Response.StatusCode = (int)HttpStatusCode.InternalServerError;
     return View("InternalServerError");
   }
} 
 In a last step we add the  ErrorController‘s views (Views/Error/NotFound.cshtml and Views/Error/InternalServerError.cshtml) that defines the (error) pages the end user will see in case of an error. The views include a partial view defined in Views/Shared/Error/NotFoundInfo.cshtml respectively Views/Shared/Error/InternalServerErrorInfo.cshtml that contains the concrete error messages. As we will see below using these partial views enables us to reuse the same error messages to handle AJAX errors.
Views/Error/NotFound.cshtml: 
@{ 
   ViewBag.Title = "Not found";
} 
@{ 
   Html.RenderPartial("Error/NotFoundInfo");
} 
Views/Shared/Error/NotFoundInfo.cshtml:
 
 The URL you have requested was not found. 
 
 Views/Error/InternalServerError.cshtml:
 
 @{
   ViewBag.Title = "Internal server error";
 }
 @{
   Html.RenderPartial("Error/InternalServerErrorInfo");
 }
 
 Views/Shared/Error/InternalServerErrorInfo.cshtml:
 
 An internal Server error occured.
 
 To handle errors occurring in (jQuery) AJAX calls we will use jQuery UI to show a dialog containing the error messages. In order to include jQuery UI we need to add two lines to Views/Shared/_Layout.cshtml:
<link href="@Url.Content("~/Content/themes/base/jquery.ui.all.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")" type="text/javascript"></script>
 
 Moreover we add the following jQuery JavaScript code (defining the global AJAX error handling) and the Razor snippet (defining the dialog containers) to Views/Shared/_Layout.cshtml:
< script type="text/javascript">
   $(function () {
     // Initialize dialogs ...
     var dialogOptions = {
       autoOpen: false,
       draggable: false,
       modal: true,
       resizable: false,
       title: "Error",
       closeOnEscape: false,
       open: function () { $(".ui-dialog-titlebar-close").hide(); }, // Hide close button
       buttons: [{
         text: "Close",
         click: function () { $(this).dialog("close"); }
       }]
     };
     $("#InternalServerErrorDialog").dialog(dialogOptions);
     $("#NotFoundInfoDialog").dialog(dialogOptions); 
      // Set up AJAX error handling ...
     $(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError)
 {
       if (jqXHR.status == 404) {
         $("#NotFoundInfoDialog").dialog("open");
       } else if (jqXHR.status == 500) {
         $("#InternalServerErrorDialog").dialog("open");
       } else {
         alert("Something unexpected happend :( ...");
       }
     });
   });
</ script>
<div id="NotFoundInfoDialog">
   @{ Html.RenderPartial("Error/NotFoundInfo"); }
 </div>
 <div id="InternalServerErrorDialog">
   @{ Html.RenderPartial("Error/InternalServerErrorInfo"); }
 </div>
 
 As you can see in the Razor snippet above we reuse the error texts defined in the partial views saved in Views/Shared/Error/.
 
 
 To test our custom errors we define the HomeController (Controllers/HomeController.cs) as follows:
 
   public class HomeController : Controller
   {
   public ActionResult Index()
   {
     return View();
   }
   public ActionResult Error500()
   {
     throw new Exception();
   }
 }
 
 and the corresponding view Views/Home/Index.cshtml:
 
 @{
   ViewBag.Title = "ViewPage1";
 } 
 
 <script type="text/javascript">
   $function () {
     $("a.ajax").click(function (event) {
       event.preventDefault();
       $.ajax({
       url: $(this).attr('href'),
     });
   });
 });
 </script> 
 
 <ul>
   <li>@Html.ActionLink("Error 404 (Not Found)", "Error404")</li>
   <li>@Html.ActionLink("Error 404 (Not Found) [AJAX]", "Error404", new { },
 new { Class = "ajax" })</li>
   <li>@Html.ActionLink("Error 500 (Internal Server Error)", "Error500")</li>
   <li>@Html.ActionLink("Error 500 (Internal Server Error) [AJAX]", "Error500", new { }, new { Class = "ajax" })</li>
 </ul>
To test the custom errors you can launch the project and click one of the four links defined in the view above. The “AJAX links” should open a dialog containing the error message and the “non-AJAX” links should redirect to a new page showing the same error message.
 Summarized this blog post shows how to set up custom errors that handle errors occurring in both AJAX requests and “non-AJAX” requests. Depending on the project, one could customize the example code shown above to handle other HTTP errors as well or to show more customized error messages or dialogs.