User.Anonymous
User.Anonymous

Reputation: 1726

Custom Error in MVC 4

I have an issue to handling error in MVC. My goal is to show in the header a "friendly" error message, but the application should be already visible. I use the override OnException on Base Controller method as following :

protected override void OnException(ExceptionContext filterContext)
{
    if (filterContext.ExceptionHandled)
        return;

    var error = new ErrorModel(filterContext.Exception);
    error.ActionName = filterContext.RouteData.Values["action"].ToString();
    error.ControllerName = filterContext.RouteData.Values["controller"].ToString();

    filterContext.Controller.TempData["ErrorInfo"] = error;

    filterContext.HttpContext.Response.Clear();
    filterContext.HttpContext.Response.StatusCode = 500;
    filterContext.ExceptionHandled = true;
    filterContext.Result = this.RedirectToAction(actionName: "DisplayError", controllerName: "Error");            

    //base.OnException(filterContext);
}

ErrorModel is a flat copy of HandleErrorInfo because all action need to be serialized.

In an ErrorController, I retrieve my model from TempData

public ActionResult DisplayError()
{
    var error = TempData["ErrorInfo"] as ErrorModel;
    ControllerContext.HttpContext.Response.StatusCode = 500;

    return PartialView("Error", error);
}

And I call my View

@using log4net;
@model Easily.MVC.Utils.ErrorModel
@{
    ViewBag.Title = "Error";
}

    <link href="@string.Format("http://{0}/easily.Ressources.Web/css/easilyCommon.min.css", System.Configuration.ConfigurationManager.AppSettings["EasilyServerName"])" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/custom.css")[email protected]("GetVersion", "Main")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/Worklist.css")[email protected]("GetVersion", "Main")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/jquery.contextMenu.css")[email protected]("GetVersion", "Main")" rel="stylesheet" type="text/css" />
    <script type="text/javascript"> window['currentPath'] = '@Url.Content("~/")'; </script>
    <script src="@string.Format("http://{0}/easily.Ressources.Web/js/easilyCommon.min.js", System.Configuration.ConfigurationManager.AppSettings["EasilyServerName"])" type="text/javascript"></script>

<fieldset class="divError">
    @if (ViewBag != null && ViewBag.Message != null)
    {
        <legend title="Erreur Easily.MVC" class="legendError">Une erreur s'est produite</legend>@*
         <span>Erreur Easily.MVC</span>*@
    }
    @if (Model != null /*&& HttpContext.Current.IsDebuggingEnabled*/)
    {
        <legend title="Erreur @Model.Exception.Message" class="legendError">Une erreur s'est produite</legend>@*
        <span>Erreur @Model.Exception.Message</span>*@
    }

    <div class="detailError">
        <h3>Detail de l'erreur</h3>
        <div class="list-sfs-holder msgError">
            @if (ViewBag != null && ViewBag.Message != null)
            {
                <div class="alert alert-error">@ViewBag.Message</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>
                    <hr />
                    <p>
                        <b>StackTrace:</b>
                    </p>
                    <div style="overflow: scroll; width: 980px;">

                            <pre>
                         @Model.Exception.StackTrace
                </pre>

                    </div>
                </div>
            }

        </div>
    </div>
</fieldset>

@{
    ILog log = LogManager.GetLogger("WorkListError");

    if (ViewBag != null && ViewBag.Message != null)
    {
        log.Error("ViewBag.Message:" + @ViewBag.Message);
    }
    if (Model != null && HttpContext.Current.IsDebuggingEnabled)
    {
        log.Error("Exception:" + Model.Exception.Message + "|" +
                   "Controller:" + Model.ControllerName + "|" +
                   "Action:" + Model.ActionName + "|" +
                   "StackTrace:" + Model.Exception.StackTrace
                 );
    }    
}

<script>

    $(document).ready(function () {
        $(".detailError").accordion({ collapsible: true, active: false, heightStyle: "content", width: '980px' });
    });

</script>

At least, for AJAX Error, I use this script :

$(document).ajaxError(function (event, jqxhr, settings, exception) {
    $("#error_content").html(jqxhr.responseText);
});

With this code, the result is as my goal @ localhost. But when I deploy this on test server, I have server message Error 500 instead my error view. So how I can modify the code to avoid error 500 and ever catch error in custom display (server can not be modified, but I can use web.config) ? And if I comment ControllerContext.HttpContext.Response.StatusCode = 500; in DisplayError, Ajax Error is not catched.

Thanks for your help.

Upvotes: 2

Views: 753

Answers (1)

user247702
user247702

Reputation: 24232

In your web.config, make sure you have the following configuration:

<configuration>
    <system.webServer>
        <httpErrors errorMode="Detailed" />
    </system.webServer>
</configuration>

The default value for errorMode is DetailedLocalOnly (docs)

Upvotes: 2

Related Questions