尝试从 asp.net 自定义错误处理程序重定向回 MVC

Trying to redirect back into MVC from the asp.net Custom Error handler

在web.config中我有以下代码:

<customErrors mode="On" defaultRedirect="~/vErrorPages/Error.html">
  <error statusCode="404" redirect="~/vErrorPages/Error404.html" />
</customErrors>

在Error.html中我有以下代码,其中Error是控制器,ErrorPage是动作方法:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="refresh" content="0; url=../Error/ErrorPage" />
  <title></title>
</head>
<body>
</body>
</html>

这很好用。它让我回到 MVC,在那里我可以提供已经像我网站的其余部分一样布局的自定义错误页面。

在阅读各种 SO posts 时,它看起来像一个 aspx 页面:

<% Server.Transfer("../Error/ErrorPage")%>

可能会更快,所以我试了一下。不好。它给出了一个 'Error executing child request' 错误,其他 SO posts 说实际上与 http 404 相同。

如果我使用 Server.Transfer 访问 .html 文件,它工作正常。看起来 MVC 路由不适用于此。由于 .aspx 页面所在的位置,我使用了上面的 ../,但这也不起作用:

<% Server.Transfer("~/Error/ErrorPage")%>

Server.Transfer 上有很多 SO post,但我没有找到从 .aspx 到 MVC 路由的,所以我想问问是否有人对此有意见。

在原始 post 之后添加以下 rism: 更新了 web.config 部分:

<customErrors mode="On" defaultRedirect="~/vErrorPages/ErrorGeneral.aspx">
  <error statusCode="404" redirect="~/vErrorPages/Error404NotFound.html" />
</customErrors>

这是错误时 web.config 重定向指向的整个 ErrorGeneral.aspx(注意:我将错误控制器的方法名称更改为 ErrorGeneral):

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="ErrorGeneral.aspx.vb" Inherits="MVC5ErrorHandling.error1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
  <% Server.Transfer("/Error/ErrorGeneral")%>
</body>
</html>

这也不行。

404是因为默认路由是controller/action/args。所以你要求一个名为“..”或“~”的控制器。你应该

<% Server.Transfer("Error/ErrorPage")%>

然后在MVC项目中注册路由为:

routes.MapPageRoute("MyErrorHandler", "Error/ErrorPage", "~/vErrorPages/Error.html");

虽然 Server.Transfer 到 html 有点奇怪,因为您不会在服务器上处理任何其他内容。

没有什么能阻止您将在 _Layout.vbhtml 中使用的 markup/CSS 应用到 Error.vbhtml。话虽这么说,而不是从该页面重定向(无论如何你应该避免滥用 Server.Transfer),通过 web.config 和 Global.asax.vb 中的 Application_Error 事件正确处理错误。通过这样做,您可以显示实际表示遇到的错误的错误页面,而不是一些通用的 "An error has occurred" 消息。

所需的 web.config 设置为:

<system.web>
    <customErrors mode="On" defaultRedirect="~/error/general" redirectMode="ResponseRewrite">
        <error statusCode="400" redirect="~/error/badrequest" />
        <error statusCode="401" redirect="~/error/unauthorized" />
        <error statusCode="403" redirect="~/error/forbidden" />
        <error statusCode="404" redirect="~/error/notfound" />
    </customErrors>
</system.web>

对于 IIS 6 及更低版本,并且

<system.webServer>
    <httpErrors errorMode="Custom">
        <remove statusCode="400" />
        <error statusCode="400" path="/errors/badrequest" responseMode="ExecuteURL" />
        <remove statusCode="401" />
        <error statusCode="401" path="/errors/unauthorized" responseMode="ExecuteURL" />
        <remove statusCode="403" />
        <error statusCode="403" path="/errors/forbidden" responseMode="ExecuteURL" />
        <remove statusCode="404" />
        <error statusCode="404" path="/errors/notfound" responseMode="ExecuteURL" />
    </httpErrors>
</system.webServer>

对于其他一切。以下是 Application_Error:

的一个相当简单的实现
Protected Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)

    Dim exception As Exception = Server.GetLastError()
    Dim httpException As HttpException = TryCast(exception, HttpException)

    Server.ClearError()

    Dim routeData As RouteData = New RouteData()
    routeData.Values("controller") = "error"
    routeData.Values("action") = "general"
    routeData.Values("exception") = exception
    Response.StatusCode = 500

    If Not IsNothing(httpException) Then

        Response.StatusCode = httpException.GetHttpCode()
        Select Case Response.StatusCode
            Case 400
                routeData.Values("action") = "badrequest"
            Case 401
                routeData.Values("action") = "unauthorized"
            Case 403
                routeData.Values("action") = "forbidden"
            Case 404
                routeData.Values("action") = "notfound"
        End Select

    End If

    Response.TrySkipIisCustomErrors = True

    Dim controller As IController = New Controllers.ErrorController()
    Dim wrapper As HttpContextWrapper = New HttpContextWrapper(Context)

    Dim rc As RequestContext = New RequestContext(wrapper, routeData)
    controller.Execute(rc)

End Sub

为此,您需要添加一个 ErrorController 和相关视图。

为了解决您关于执行异常操作的评论,假设您已经像这样定义了常规操作:

Imports System.Web.Mvc

Namespace Controllers
    Public Class ErrorController
        Inherits Controller

        Function General(ByVal exception As Exception) As ActionResult
            Return View(exception)
        End Function

        ' ... the rest of the actions 

    End Class
End Namespace

那么您可以在视图中使用像这样简单的东西:

@ModelType Exception

@Code
    ViewBag.Title = "Error"
End Code

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<p>
    Exception message: @Model.Message
</p>

此示例假定您要显示来自捕获的异常的消息。您可能不会在实时站点上这样做,但您可以添加一些内容来检查管理级别的角色,并且只向这些用户显示消息。