Вопрос

I've made some modifications to Global.asax so that I can show custom error pages (403, 404, and 500) Here's the code:

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            //FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

        protected void Application_Error(object sender, EventArgs e)
        {
            if (Context.IsCustomErrorEnabled)
            {
                ShowCustomErrorPage(Server.GetLastError());
            }
        }

        private void ShowCustomErrorPage(Exception exception)
        {
            HttpException httpException = exception as HttpException;
            if (httpException == null)
            {
                httpException = new HttpException(500, "Internal Server Error", exception);
            }

            Response.Clear();
            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", "Error");
            routeData.Values.Add("fromAppErrorEvent", true);

            switch (httpException.GetHttpCode())
            {
                case 403:
                    routeData.Values.Add("action", "AccessDenied");
                    break;

                case 404:
                    routeData.Values.Add("action", "NotFound");
                    break;

                case 500:
                    routeData.Values.Add("action", "ServerError");
                    break;

                default:
                    routeData.Values.Add("action", "DefaultError");
                    routeData.Values.Add("httpStatusCode", httpException.GetHttpCode());
                    break;
            }

            Server.ClearError();

            IController controller = new ErrorController();
            controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
        }
    }

I've also added the following to my Web.Config:

<customErrors mode="On">
    <!-- There is custom handling of errors in Global.asax -->
</customErrors>

The custom error pages show up correctly, and ELMAH will correctly log the error that was (purposefully) thrown. But ELMAH also catches and logs an additional error:

System.InvalidOperationException: The view 'Error' or its master was not found or no view engine supports the searched locations. The following locations were searched: ~/Views/account/Error.aspx ~/Views/account/Error.ascx ~/Views/Shared/Error.aspx ~/Views/Shared/Error.ascx ~/Views/account/Error.cshtml ~/Views/account/Error.vbhtml ~/Views/Shared/Error.cshtml ~/Views/Shared/Error.vbhtml

My first instincts led me to disabling the global HandleErrorAttribute in the filter configuration. And, similar SO questions such as:MVC problem with custom error pages led me to believe my suspicions were right. But even after disabling the global HandleErrorAttribute I am still getting the Error that the Error view could not be found! What gives? My only other hunch is that my base controller derives from System.Web.Mvc.Controller I tried to examine the source to see if the HandleErrorAttribute is applied to System.Web.Mvc.Controller but couldn't glean anything...

UPDATE: I tried overriding my base controller to mark exceptions as handled like this:

protected override void OnException(ExceptionContext filterContext)
{
    filterContext.ExceptionHandled = true;
    base.OnException(filterContext);
}

but that didn't solve the problem.

UPDATE2: I placed an Error.aspx file into the shared views, just to see what would happen. When it's there, ELMAH logs the forced exception, and then the shared view is served up - it never reaches Application_Error() .... not too sure what to make of it.

Это было полезно?

Решение

Finally got it working to my satisfaction...

The Elmah.Mvc package applies a "hidden" error handler. I've disabled this by adding the following line in web.config <appSettings> (the value was set to "false" by default from nuget install)

<add key="elmah.mvc.disableHandleErrorFilter" value="true" />

So, now my errors propagate up to Application_Error and are logged by Elmah, bypassing the Elmah filter, and display the proper error page (not the one in /shared/error.cshtml)

Другие советы

If you are running in IIS 7 integrated mode, you will need to add Response.TrySkipIisCustomErrors = true; in Application_Error. Otherwise IIS will still redirect the client to a custom error page, despite anything you do in code.

See here for additional details: http://www.west-wind.com/weblog/posts/2009/Apr/29/IIS-7-Error-Pages-taking-over-500-Errors

Edit: here's the body of my Application_Error:

if (HttpContext.Current != null)
{
    Server.ClearError();
    Response.TrySkipIisCustomErrors = true;
    RouteData data = new RouteData();
    data.Values.Add("controller", "Error");
    data.Values.Add("action", "Error");
    IController controller = new MyApp.Controllers.ErrorController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), data));
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top