How to get ride of customErrors completely in Web.

2019-08-09 06:11发布

问题:

I implemented a custom error handler for my MVC5 project and everything would be fine if it wasn't of the customErrors attribute. I'll explain: When I got an error in the application, I catch it inside void Application_Error from Global.asax like this:

protected void Application_Error(object sender, EventArgs e)
        {
            var httpContext = ((HttpApplication)sender).Context;
            ExecuteErrorController(httpContext, Server.GetLastError());
        }

public static void ExecuteErrorController(HttpContext httpContext, Exception exception)
        {
            if (!exception.Message.Contains("NotFound") && !exception.Message.Contains("ServerError"))
            {
                var routeData = new RouteData();
                routeData.Values["area"] = "Administration";
                routeData.Values["controller"] = "Error";
                routeData.Values["action"] = "Insert";
                routeData.Values["exception"] = exception;

                using (Controller controller = new ErrorController())
                {
                    ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
                }
            }
        }

Then, inside my ErrorController I do:

     public ActionResult Insert(Exception exception)
            {
                ErrorSignal.FromCurrentContext().Raise(exception);
                Server.ClearError();
                Response.Clear();

                switch (Tools.GetHttpCode(exception)) // (int)HttpStatusCode.NotFound;
                {
                    case 400:
                        return RedirectToAction("BadRequest");
                    case 401:
                        return RedirectToAction("Unauthorized");
                    case 403:
                        return RedirectToAction("Forbidden");
                    case 404:
                        return RedirectToAction("NotFound");
                    case 500:
                        return RedirectToAction("ServerError");
                    default:
                        return RedirectToAction("DefaultError");
                }
            }

    public ActionResult Unauthorized()
            {
                return View();
            }
...

So the first time, everything works perfectly But !! The code repeat itself because the NotFound or ServerError page aren't in the Shared folder. Those page are supposed to be set in customErrors attribute BUT the thing is I don't need it at all. I finally got this error: ERR_TOO_MANY_REDIRECTS because of that.

I read all day to find any answer about that, and it seams that everyone who published their code do the same kind of pattern as mine, and no matter what I tried, nothing works.

Notice my desperate if condition: if (!exception.Message.Contains("NotFound") && !exception.Message.Contains("ServerError"))

I also comment those two lines in the global.asax because everywhere I read, it says we need to remove them in order to get this done.

//GlobalConfiguration.Configure(WebApiConfig.Register);
//FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

Also, because of the desparate if, I got this answer:

Runtime Error

Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed. 

Details: To enable the details of this specific error message to be viewable on the local server machine, please create a <customErrors> tag within a "web.config" configuration file located in the root directory of the current web application. This <customErrors> tag should then have its "mode" attribute set to "RemoteOnly". To enable the details to be viewable on remote machines, please set "mode" to "Off".


<!-- Web.Config Configuration File -->

<configuration>
    <system.web>
        <customErrors mode="RemoteOnly"/>
    </system.web>
</configuration>

I also tried Response.TrySkipIisCustomErrors = true; and it doesn't work!

So, how can I get ride of customErrors completely and manage my own error handler in my project?

回答1:

Alright, thanks to the comment of RoteS. I finally found what I need to get this done !

The way I did it by Executing the ErrorController wasn't good.

using (Controller controller = new ErrorController())
                {
                    ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
                }

I found that by using ServerTransfert instead, we can get ride of customErrors attribute. Here is the final solution (tested):

protected void Application_Error(object sender, EventArgs e)
        {
            // Response.TrySkipIisCustomErrors = true; I don't know if I will need it someday.
            var httpContext = ((HttpApplication)sender).Context;
            var exception = Server.GetLastError();

            ErrorSignal.FromCurrentContext().Raise(exception);
            Server.ClearError();
            Response.Clear();
            string relativePath = "~/Administration/Error/{0}";
            switch (Tools.GetHttpCode(exception))
            {
                case (int)HttpStatusCode.BadRequest:
                    Server.TransferRequest(string.Format(relativePath, "BadRequest"));
                    break;
                case (int)HttpStatusCode.Unauthorized:
                    Server.TransferRequest(string.Format(relativePath, "Unauthorized"));
                    break;
                case (int)HttpStatusCode.Forbidden:
                    Server.TransferRequest(string.Format(relativePath, "Forbidden"));
                    break;
                case (int)HttpStatusCode.NotFound:
                    Server.TransferRequest(string.Format(relativePath, "NotFound"));
                    break;
                case (int)HttpStatusCode.InternalServerError:
                    Server.TransferRequest(string.Format(relativePath, "ServerError"));
                    break;
                default:
                    Server.TransferRequest(string.Format(relativePath, "DefaultError"));
                    break;
            }
        }

Thanks to RoteS for the comment that pointed me in the right direction.

David