asp.net-mvc ASP.NET MVC4 CustomErrors DefaultRedirect 被忽略

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17636806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 03:01:25  来源:igfitidea点击:

ASP.NET MVC4 CustomErrors DefaultRedirect Ignored

asp.net-mvcasp.net-mvc-3asp.net-mvc-4

提问by therealmitchconnors

I have an MVC 4 app, using a custom HandleErrorAttribute to handle only custom exceptions. I would like to intercept the default 404 and other non-500 error pages and replace them with something more attractive. To that end, I added the following to my Web.config:

我有一个 MVC 4 应用程序,使用自定义 HandleErrorAttribute 仅处理自定义异常。我想拦截默认的 404 和其他非 500 错误页面并用更有吸引力的东西替换它们。为此,我在 Web.config 中添加了以下内容:

<system.web>
    <customErrors mode="On" defaultRedirect="~/Error/Index" />
...
</ system.web>

I have an Error controller with an Index method and corresponding view, but still I get the default 404 error page. I have also tried setting my defaultRedirectto a static html file to no avail. I have tried adding error handling specific to 404's inside <customErrors>, and I even tried modifying the routes programattically, all with no results. What am I missing? Why is ASP ignoring my default error handling?

我有一个带有索引方法和相应视图的错误控制器,但我仍然得到默认的 404 错误页面。我也尝试将 my 设置defaultRedirect为静态 html 文件无济于事。我尝试在内部添加特定于 404 的错误处理<customErrors>,我什至尝试以编程方式修改路由,但都没有结果。我错过了什么?为什么 ASP 会忽略我的默认错误处理?

Note: I noticed earlier that I cannot test my CustomHandleErrorAttribute locally, even with <customErrors mode="On". It does work when I hit it on my server from my dev box though... not sure if that is related. This guyhad the same problem.

注意:我之前注意到我无法在本地测试我的 CustomHandleErrorAttribute,即使使用<customErrors mode="On". 当我从我的开发箱在我的服务器上点击它时它确实有效......但不确定这是否相关。 这家伙也有同样的问题。

采纳答案by Nirmal Subedi

This should work :

这应该工作:

1. Web.Config

1. 网页配置

<customErrors mode="On"
   defaultRedirect="~/Views/Shared/Error.cshtml">

  <error statusCode="403"
    redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />

  <error statusCode="404"
    redirect="~/Views/Shared/FileNotFound.cshtml" />

</customErrors>

2. Registered HandleErrorAttribute as a global action filter in the FilterConfig class as follows

2.在FilterConfig类中注册HandleErrorAttribute作为全局动作过滤器如下

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CustomHandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }

If that dont work then, Try to make yourself transfer the response by checking status codes like the Following in the Global.asax: at least it must work.

如果那不起作用,请尝试通过检查 Global.asax 中的以下状态代码来让自己传输响应:至少它必须工作。

void Application_EndRequest(object sender, EventArgs e)
{
    if (Response.StatusCode == 401)
    {
        Response.ClearContent();
        Server.Transfer("~/Views/Shared/UnauthorizedAccess.cshtml");
    }
}

回答by Imad Alazani

I am going little off topic. I thought this is bit important to explain.

我很少离题。我认为解释这一点很重要。

enter image description here

在此处输入图片说明

If you pay attention to the above highlighted part. I have specified the order of the Action Filter. This basically describes the order of execution of Action Filter. This is a situation when you have multiple Action Filters implemented over Controller/Action Method

如果您注意上面突出显示的部分。我已经指定了操作过滤器的顺序。这基本上描述了 Action Filter 的执行顺序。这是当您通过控制器/操作方法实现多个操作过滤器时的情况

enter image description here

在此处输入图片说明

This picture just indicates that let's say you have two Action Filters. OnActionExecutionwill start to execute on Priority and OnActionExecutedwill start from bottom to Top. That means in case of OnActionExecutedAction Filter having highest order will execute first and in case of OnActionExecutingAction Filter having lowest order will execute first. Example below.

这张图片只是表明假设您有两个操作过滤器。OnActionExecution将开始按优先级执行,并OnActionExecuted从下到上开始。这意味着在OnActionExecuted具有最高顺序的操作过滤器的情况下将首先执行,并且在OnActionExecuting具有最低顺序的操作过滤器的情况下将首先执行。下面举例。

public class Filter1 : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

//Execution will start here - 1

//执行将从这里开始 - 1

        base.OnActionExecuting(filterContext);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {

//Execution will move here - 5

//执行会移到这里 - 5

        base.OnActionExecuted(filterContext);
    }
}

public class Filter2 : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

//Execution will move here - 2

//执行会移到这里 - 2

        base.OnActionExecuting(filterContext);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {

//Execution will move here - 4

//执行会移到这里 - 4

        base.OnActionExecuted(filterContext);
    }
}

[HandleError]
public class HomeController : Controller
{
    [Filter1(Order = 1)]
    [Filter2(Order = 2)]
    public ActionResult Index()
    {

//Execution will move here - 3

//执行会移到这里 - 3

        ViewData["Message"] = "Welcome to ASP.NET MVC!";

        return View();
    }
}

You may already aware that there are different types of filters within MVC framework. They are listed below.

您可能已经意识到 MVC 框架中有不同类型的过滤器。它们在下面列出。

  1. Authorization filters

  2. Action filters

  3. Response/Result filters

  4. Exception filters

  1. 授权过滤器

  2. 动作过滤器

  3. 响应/结果过滤器

  4. 异常过滤器

Within each filter, you can specify the Order property. This basically describes the order of execution of the Action Filters.

在每个过滤器中,您可以指定 Order 属性。这基本上描述了操作过滤器的执行顺序。

Back to the original Query

返回原始查询

This works for me. This is very easy and no need to consider any change in Web.Config or Register the Action Filter in Global.asax file.

这对我有用。这非常简单,无需考虑 Web.Config 中的任何更改或在 Global.asax 文件中注册操作过滤器。

ok. So, First I am creating a simple Action Filter. This will handle Ajax and Non Ajax requests.

好的。所以,首先我要创建一个简单的Action Filter。这将处理 Ajax 和非 Ajax 请求。

public class MyCustomErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        filterContext.ExceptionHandled = true;
        var debugModeMsg = filterContext.HttpContext.IsDebuggingEnabled
                               ? filterContext.Exception.Message +
                                 "\n" +
                                 filterContext.Exception.StackTrace
                               : "Your error message";

//This is the case when you need to handle Ajax requests

//当你需要处理 Ajax 请求时就是这种情况

        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    error = true,
                    message = debugModeMsg
                }
            };
        }

//This is the case when you handle Non Ajax request

//当你处理非 Ajax 请求时就是这种情况

        else
        {
            var routeData = new RouteData();
            routeData.Values["controller"] = "Error";
            routeData.Values["action"] = "Error";
            routeData.DataTokens["area"] = "app";
            routeData.Values["exception"] = debugModeMsg;
            IController errorsController = new ErrorController();
            var exception = HttpContext.Current.Server.GetLastError();
            var httpException = exception as HttpException;
            if (httpException != null)
            {
                Response.StatusCode = httpException.GetHttpCode();
                switch (System.Web.HttpContext.Current.Response.StatusCode)
                {
                    case 404:
                        routeData.Values["action"] = "Http404";
                        break;
                }
            }

            var rc = new RequestContext
                         (
                             new HttpContextWrapper(HttpContext.Current),
                             routeData
                         );
            errorsController.Execute(rc);
        }
        base.OnException(filterContext);
    }
}

Now you can implement this Action Filter on Controller as well as on the Action only.Example:

现在你可以在 Controller 和 Action only 上实现这个 Action Filter。例如:

enter image description here

在此处输入图片说明

Hope this should help you.

希望这对你有帮助。

回答by MatrixRonny

I want to share my knowledge after investigating this problem. Any comments that help improve my statements are welcomed.

我想在调查这个问题后分享我的知识。欢迎任何有助于改进我的陈述的评论。

In ASP.NET MVC, there are three layers that handle HTTP requests in the following order (response is transferred in reverse order):

在 ASP.NET MVC 中,有三层按以下顺序处理 HTTP 请求(响应以相反的顺序传输):

  1. IIS (HTTP Layer)

  2. ASP.NET (Server Layer)

  3. Controller (MVC Layer)

  1. IIS(HTTP 层)

  2. ASP.NET(服务器层)

  3. 控制器(MVC 层)

All of these layers have error handling, but each layer does it differently. I'll start with IIS.

所有这些层都有错误处理,但每一层的处理方式不同。我将从 IIS 开始。

IIS Layer

IIS层

The simplest example of how IIS handles an error is to request a non existing .html file from your server, using the browser. The address should look like:

IIS 如何处理错误的最简单示例是使用浏览器从您的服务器请求一个不存在的 .html 文件。地址应如下所示:

http://localhost:50123/this_does_not_exist.html

http://localhost:50123/this_does_not_exist.html

Notice the title of the browser tab, for example: IIS 10.0 Detailed Error - 404.0 - Not Found.

请注意浏览器选项卡的标题,例如:IIS 10.0 详细错误 - 404.0 - 未找到

ASP.NET Layer

ASP.NET 层

When IIS receives a HTTP request, if the URL ends with .aspx, it forwards it to ASP.NET since it is registered to handle this extension. The simplest example of how ASP.NET handles an error is to request a non existing .aspx file from your server, using the browser. The address should look like:

当 IIS 收到 HTTP 请求时,如果 URL 以 .aspx 结尾,它会将其转发到 ASP.NET,因为它已注册以处理此扩展名。ASP.NET 如何处理错误的最简单示例是使用浏览器从您的服务器请求一个不存在的 .aspx 文件。地址应如下所示:

http://localhost:50123/this_does_not_exist.aspx

http://localhost:50123/this_does_not_exist.aspx

Notice the Version Informationdisplayed at the bottom of the page, indicating the version of ASP.NET.

请注意页面底部显示的版本信息,指示 ASP.NET 的版本。

The customErrorstag was originally created for ASP.NET. It has effect onlywhen the response is created by ASP.NET internal code. This means that it does not affect responses created from application code. In addition, if the response returned by ASP.NET has no content and has an error status code (4xx or 5xx), then IIS will replace the response according to the status code. I'll provide some examples.

的customErrors标签最初是为ASP.NET创建。当响应由 ASP.NET 内部代码创建时才有效。这意味着它不会影响从应用程序代码创建的响应。另外,如果 ASP.NET 返回的响应没有内容并且有错误状态码(4xx 或 5xx),那么 IIS 会根据状态码替换响应。我会提供一些例子。

If the Page_Loadmethod contains Response.StatusCode = 404, then the content is displayed normally. If additional code Response.SuppressContent = trueis added, then IIS intervenes and handles 404 error in the same way as when requesting "this_does_not_exist.html". An ASP.NET response with no content and status code 2xx is not affected.

如果Page_Load方法包含Response.StatusCode = 404,则内容正常显示。如果添加了其他代码Response.SuppressContent = true,则 IIS 会以与请求“this_does_not_exist.html”时相同的方式进行干预并处理 404 错误。没有内容和状态代码 2xx 的 ASP.NET 响应不受影响。

When ASP.NET is unable to complete the request using application code, it will handle it using internal code. See the following examples.

当 ASP.NET 无法使用应用程序代码完成请求时,它将使用内部代码处理它。请参阅以下示例。

If an URL cannot be resolved, ASP.NET generates a response by itself. By default, it creates a 404 response with HTML body containing details about the problem. The customErrors can be used to create a 302 (Redirect) response instead. However, accessing a valid URL that causes ASP.NET to return a 404 response does not trigger the redirect specified by customErrors.

如果无法解析 URL,ASP.NET 会自行生成响应。默认情况下,它会创建一个带有 HTML 正文的 404 响应,其中包含有关问题的详细信息。customErrors 可用于创建 302(重定向)响应。但是,访问导致 ASP.NET 返回 404 响应的有效 URL 不会触发 customErrors 指定的重定向。

The same happens when ASP.NET catches an exception from application code. By default, it creates a 500 response with HTML body containing details about the source code that caused the exception. Again, the customErrors can be used to generate a 302 (Redirect) response instead. However, creating a 500 response from application code does not trigger the redirect specified by customErrors.

当 ASP.NET 从应用程序代码中捕获异常时,也会发生同样的情况。默认情况下,它会创建一个带有 HTML 正文的 500 响应,其中包含有关导致异常的源代码的详细信息。同样,customErrors 可用于生成 302(重定向)响应。但是,从应用程序代码创建 500 响应不会触发 customErrors 指定的重定向。

The defaultRedirectand errortags are pretty straight-forth to understand considering what I just said. The error tag is used to specify a redirect for a specific status code. If there is no corresponding error tag, then the defaultRedirect will be used. The redirect URL can point to anything that the server can handle, including controller action.

考虑到我刚才所说的,defaultRedirecterror标签非常容易理解。错误标记用于指定特定状态代码的重定向。如果没有相应的错误标记,则将使用 defaultRedirect。重定向 URL 可以指向服务器可以处理的任何内容,包括控制器操作。

MVC Layer

MVC层

With ASP.NET MVC things get more complicated. Firstly, there may be two "Web.config" files, one in the root and one in the Views folder. I want to note that the default "Web.config" from Views does two things of interest to this thread:

使用 ASP.NET MVC 事情变得更加复杂。首先,可能有两个“Web.config”文件,一个在根目录中,一个在 Views 文件夹中。我想指出,来自 Views 的默认“Web.config”对这个线程做了两件有趣的事情:

  • It disables handling URLs to .cshtml files (webpages:Enabled set to false)
  • It prevents direct access to any content inside the Views folder (BlockViewHandler)
  • 它禁止处理 .cshtml 文件的 URL(网页:启用设置为 false)
  • 它可以防止直接访问 Views 文件夹中的任何内容 (BlockViewHandler)

In the case of ASP.NET MVC, the HandleErrorAttributemay be added to GlobalFilters, which also takes into account the value of modeattribute of the customErrors tag from the root "Web.config". More specifically, when the setting is On, it enables error handling at MVC Layer for uncaught exceptions in controller/action code. Rather than forwarding them to ASP.NET, it renders Views/Shared/Error.cshtml by default. This can be changed by setting the View property of HandleErrorAttribute.

在 ASP.NET MVC 的情况下,HandleErrorAttribute可以添加到GlobalFilters,这也考虑了来自根“Web.config”的 customErrors 标记的mode属性的值。更具体地说,当设置为 On 时,它会在 MVC 层为控制器/操作代码中未捕获的异常启用错误处理。默认情况下,它不会将它们转发到 ASP.NET,而是呈现 Views/Shared/Error.cshtml。这可以通过设置 HandleErrorAttribute 的 View 属性来改变。

Error handling at MVC Layer starts after the controller/action is resolved, based on the Request URL. For example, a request that doesn't fulfill the action's parameters is handled at MVC Layer. However, if a POST request has no matching controller/action that can handle POST, then the error is handled at ASP.NET Layer.

MVC 层的错误处理在控制器/操作解决后开始,基于请求 URL。例如,不满足操作参数的请求在 MVC 层处理。但是,如果 POST 请求没有可以处理 POST 的匹配控制器/操作,则在 ASP.NET 层处理错误。

I have used ASP.NET MVC 5 for testing. There seems to be no difference between IIS and IIS Express regarding error handling.

我已经使用 ASP.NET MVC 5 进行测试。关于错误处理,IIS 和 IIS Express 之间似乎没有区别。

Answer

回答

The only reason I could think of why customErrors is not considered for non-500 status codes is because they are created with HttpStatusCodeResponse. In this case, the response is created by the application code and is not handled by ASP.NET, but rather IIS. At this point configuring an alternative page is pointless. Here is an example code that reproduces this behavior:

我能想到为什么不考虑非 500 状态代码的 customErrors 的唯一原因是因为它们是使用 HttpStatusCodeResponse 创建的。在这种情况下,响应由应用程序代码创建,不由 ASP.NET 处理,而是由 IIS 处理。此时配置一个替代页面是没有意义的。这是重现此行为的示例代码:

public ActionResult Unhandled404Error()
{
    return new HttpStatusCodeResult(HttpStatusCode.NotFound);
}

In such scenario, I recommend implementing an ActionFilterAttributethat will override OnResultExecutedand do something like the following:

在这种情况下,我建议实现一个ActionFilterAttribute来覆盖OnResultExecuted并执行以下操作:

int statusCode = filterContext.HttpContext.Response.StatusCode;
if(statusCode >= 400)
{
    filterContext.HttpContext.Response.Clear();
    filterContext.HttpContext.Response.Redirect("/Home/Index");
}

The implemented ActionFilterAttribute should be added to GlobalFilters.

已实现的 ActionFilterAttribute 应添加到 GlobalFilters。

回答by Camilo Gómez

To me, it works deleting the default Error.cshtml file, now it is taking the custom Error defaultRedirect page in Web.config.

对我来说,它可以删除默认的 Error.cshtml 文件,现在它使用 Web.config 中的自定义 Error defaultRedirect 页面。

回答by Venkata Tata

I am not sure this answer will help you but this a simple way... I placed error.html in / and turned mode to on for custom errors in web config and this works perfectly...

我不确定这个答案会帮助你,但这是一个简单的方法......我将 error.html 放在 / 并打开模式来处理 web 配置中的自定义错误,这非常有效......

  <system.web>
    <customErrors defaultRedirect="~/Error.html" mode="On" />
  </system.web>

this error.html is a basic html page with head and body..

这个 error.html 是一个带有头部和正文的基本 html 页面。

回答by chamara

Create a Controller ErrorController.

创建一个控制器 ErrorController。

 public class ErrorController : Controller
    {
        //
        // GET: /Error/

        public ActionResult Index()
        {
            return View();
        }
}

Create the Index view for the action.

为操作创建索引视图。

in Web.config

在 Web.config 中

<customErrors mode="On">
      <error statusCode="404" redirect="Error/Index"/>
</customErrors>

When you are handling errors in your code/logic

当您处理代码/逻辑中的错误时

[HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Message = "Modify this template to jump-start application.";

            return View("Index2");
        }
}

[HandleError] attribute - will redirected to the Error.cshtml page inside shared folder.

[HandleError] 属性 - 将重定向到共享文件夹内的 Error.cshtml 页面。