ChatGPT解决这个技术问题 Extra ChatGPT

如何使自定义错误页面在 ASP.NET MVC 4 中工作

我想要为 500、404 和 403 显示自定义错误页面。这是我所做的:

在 web.config 中启用自定义错误,如下所示: 在FilterConfig类中注册HandleErrorAttribute作为全局动作过滤器如下: public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomHandleErrorAttribute()); filters.Add(new AuthorizeAttribute());为上述每条消息创建了一个自定义错误页面。 500 的默认值已开箱即用。在每个自定义错误页面视图中声明该页面的模型是 System.Web.Mvc.HandleErrorInfo

对于 500,它显示自定义错误页面。对于其他人,它没有。

有什么我想念的吗?

当我阅读 HandleErrorAttribute 类的 OnException 方法中的代码时,看起来这并不是显示自定义错误的全部,它只处理 500 个。

我该怎么做才能处理其他错误?

此设置的奇怪之处在于您重定向到视图,而不是控制器操作。例如,谁应该渲染这些视图并传入模型?只是想。
这里的大多数答案要么不能处理所有情况,要么导致 Web 服务器以“不正确”的方式响应,即重定向到错误页面而不是返回错误响应。如果您关心服务器以 Web 服务器所期望的方式响应,那么这里有一篇非常详细的文章:benfoster.io/blog/aspnet-mvc-custom-error-pages。请注意,它不像这里的答案那么简单,所以如果你想要一个简单的答案,只需使用下面的答案之一。
这是另一篇关于 asp.net 错误处理的各种技术的精彩文章dusted.codes/…

k
kyrylomyr

我当前的设置(在 MVC3 上,但我认为它仍然适用)依赖于 ErrorController,所以我使用:

<system.web>
    <customErrors mode="On" defaultRedirect="~/Error">
      <error redirect="~/Error/NotFound" statusCode="404" />
    </customErrors>
</system.web>

控制器包含以下内容:

public class ErrorController : Controller
{
    public ViewResult Index()
    {
        return View("Error");
    }
    public ViewResult NotFound()
    {
        Response.StatusCode = 404;  //you may want to set this to 200
        return View("NotFound");
    }
}

以及您实现它们的方式的视图。不过,我倾向于添加一些逻辑,以在应用程序处于调试模式时显示堆栈跟踪和错误信息。所以 Error.cshtml 看起来像这样:

@model System.Web.Mvc.HandleErrorInfo
@{
    Layout = "_Layout.cshtml";
    ViewBag.Title = "Error";
}
<div class="list-header clearfix">
    <span>Error</span>
</div>
<div class="list-sfs-holder">
    <div class="alert alert-error">
        An unexpected error has occurred. Please contact the system administrator.
    </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>
            <div style="overflow:scroll">
                <pre>
                    @Model.Exception.StackTrace
                </pre>
            </div>
        </div>
    }
</div>

您是否必须为此 Pablo 在 Global.asax 中的 Application_Error 中添加任何内容?
根据我的经验,控制器中的代码似乎没有执行。 MVC4 - 在不同的控制器中抛出 System.Exception 将使 Error.cshtml 文件呈现,但不会通过 ErrorController。还有其他人遇到这种情况吗?
对于发现这有帮助但需要更多背景信息的其他人; 标记位于 web.config 中的 内。
其他人的更新- 显然我的问题正在发生,因为我在 CustomerErrors 元素上有 redirectMode="ResponseRewrite"
看在上帝的份上,请忽略代码中 //you may want to set this to 200 的注释。不要那样做!
M
Machinegon

我已经完成了 pablo 解决方案,但我总是遇到错误(MVC4)

未找到视图“错误”或其主视图,或者没有视图引擎支持搜索的位置。

要摆脱这种情况,请删除该行

 filters.Add(new HandleErrorAttribute());

在 FilterConfig.cs 中


我到处寻找解决这个问题。这终于有了答案。我知道它为什么要这样做,但对于我来说,我不能,没有像其他人所说的那样彻底思考。当我说谢谢你指出这一点时,我想我和 360Airwalk 一样痛苦。传奇!
这是一种选择,错误控制器工作正常。但似乎当您在 FilterConfig.cs 中注册过滤器时,它会在共享和原始控制器的视图文件夹中查找 Error.cshtml。当您将 Error.cshtml 更改为我们的自定义 ErrorController 以外的任何内容时。但是有一个地方你可以添加这个注册,它是 global.asax.cs。如果您在 global.asax.cs 的 RegisterGlobalFilters(GlobalFilterCollection filters) 函数中添加提到的行并从 FilterConfig.cs 中删除,它会起作用。
我认为这与过滤器注册的顺序有关。保留错误控制器并将过滤器注册移动到 global.asax.cs。 public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); }
B
Brandon Osborne

我做的事情比发布的其他解决方案需要更少的编码。

首先,在我的 web.config 中,我有以下内容:

<customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
   <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
   <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
</customErrors>

控制器(/Controllers/ErrorPageController.cs)包含以下内容:

public class ErrorPageController : Controller
{
    public ActionResult Oops(int id)
    {
        Response.StatusCode = id;

        return View();
    }
}

最后,视图包含以下内容(为简单起见已删除,但它可以包含:

@{ ViewBag.Title = "糟糕!遇到错误"; }

@Response.Status

可能原因:

  • 浸信会解释:你的生活中一定有罪。其他人打开它都很好。
  • 长老会解释:你打开这个链接不是上帝的旨意。< br>
  • 信仰解释: 你缺乏打开这个链接的信仰。你的负面言论阻止了你意识到这个链接的实现。
  • 魅力解释:你已经松了!被命令打开!
  • 一神论解释:所有链接都是平等的,所以如果这个链接不起作用对你来说,随意尝试其他可能会给你带来快乐和满足感的链接。
  • 佛教解释: .........................
  • 圣公会的解释: 你是说你反对同性恋吗?
  • 基督教科学解释:那里真的是没有链接。
  • 无神论者的解释:你认为这个链接存在的唯一原因是因为你需要发明它。
  • 教会辅导员的解释:当链接打不开时,你有什么感觉?


HTTP @Response.StatusCode - @Response.StatusDescription

就这么简单。它可以轻松扩展以提供更详细的错误信息,但 ELMAH 会为我处理这些状态码 & statusDescription 是我通常需要的。


我认为“~/ErrorPage/Oops/404”的.config文件中的重定向可能应该是“~/ErrorPage/Oops?404”吧?至少这对我有用。也许这仅取决于路由。
如何模拟 IIS 引发的错误。无论是 500 还是 504。在 ASP.Net MVC 中做什么 - 5 代码来模拟来自 IIS 的异常,以便我可以测试我的自定义错误页面
T
TylerH

这里似乎有许多步骤混杂在一起。我会提出我从头开始做的事情。

创建 ErrorPage 控制器 public class ErrorPageController : Controller { public ActionResult Index() { return View(); } 公共 ActionResult Oops(int id) { Response.StatusCode = id;返回视图(); } } 为这两个动作添加视图(右键单击 -> 添加视图)。这些应该出现在名为 ErrorPage 的文件夹中。在 App_Start 中打开 FilterConfig.cs 并注释掉错误处理过滤器。 public static void RegisterGlobalFilters(GlobalFilterCollection filters) { // 移除这个过滤器,因为我们想通过 ErrorPage 控制器自己处理错误 //filters.Add(new HandleErrorAttribute());在 web.config 中添加以下 条目,在 System.Web 测试(当然)。在您的代码中抛出一个未处理的异常,并看到它转到 id 为 500 的页面,然后使用指向不存在的页面的 URL 来查看 404。


我收到此错误 An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated. 我从您的代码中获取的所有内容都在 web.config 文件中,我添加了 <error redirect = "~/ControllerName/ActionName" statusCode="404"/> 并且它运行良好:) 其余代码来自@Pablo 的答案。我正在使用 MVC 5 和实体框架 6。我没有从 FilterConfig.cs 中删除 filters.Add(new HandleErrorAttribute())
如何模拟 IIS 引发的错误。无论是 500 还是 504。在 ASP.Net MVC 中做什么 - 5 代码来模拟来自 IIS 的异常,以便我可以测试我的自定义错误页面
此外,如何抛出未处理的异常(步骤 5)。我是编码新手,请指导。
还是不适合我?路由呢?我是否也需要为错误页面添加路由?如果我点击页面:localhost:84/Enforcer/blah 我会被重定向到:localhost:84/Enforcer/Enforcer/Error/NotFound?aspxerrorpath=/… 错误页面看起来像 Asp.NET 提供的标准错误页面。有任何想法吗?
webconfig 中的 customerrors 元素应该对此进行处理。您的(项目创建的)默认路由代码应该可以正常工作。
m
maxspan

我会推荐使用 Global.asax.cs 文件。

 protected void Application_Error(Object sender, EventArgs e)
{
    var exception = Server.GetLastError();
    if (exception is HttpUnhandledException)
    {
        Server.Transfer("~/Error.aspx");
    }
    if (exception != null)
    {
        Server.Transfer("~/Error.aspx");
    }
    try
    {
        // This is to stop a problem where we were seeing "gibberish" in the
        // chrome and firefox browsers
        HttpApplication app = sender as HttpApplication;
        app.Response.Filter = null;
    }
    catch
    {
    }
}

我不认为你可以在 MVC 中做一个 Server.Transfer() 。您是否认为 OP 有一个混合站点?
为什么我们要在 mvc 中使用 Application_Error?我们有类似 [handleerror] 属性的选项和重定向 url 选项。 application_error 有什么特定的优势吗?
我们应该在 MVC 中使用 HandleErrorAttribute 并通过重写 OnException 方法,我们可以以更好的方式处理它们
u
user3380909

基于 maxspan 发布的答案,我整理了一个最小的 sample project on GitHub,显示了所有工作部分。

基本上,我们只需向 global.asax.cs 添加一个 Application_Error 方法来拦截异常并让我们有机会重定向(或更准确地说,传输请求)到自定义错误页面。

    protected void Application_Error(Object sender, EventArgs e)
    {
        // See http://stackoverflow.com/questions/13905164/how-to-make-custom-error-pages-work-in-asp-net-mvc-4
        // for additional context on use of this technique

        var exception = Server.GetLastError();
        if (exception != null)
        {
            // This would be a good place to log any relevant details about the exception.
            // Since we are going to pass exception information to our error page via querystring,
            // it will only be practical to issue a short message. Further detail would have to be logged somewhere.

            // This will invoke our error page, passing the exception message via querystring parameter
            // Note that we chose to use Server.TransferRequest, which is only supported in IIS 7 and above.
            // As an alternative, Response.Redirect could be used instead.
            // Server.Transfer does not work (see https://support.microsoft.com/en-us/kb/320439 )
            Server.TransferRequest("~/Error?Message=" + exception.Message);
        }

    }

错误控制器:

/// <summary>
/// This controller exists to provide the error page
/// </summary>
public class ErrorController : Controller
{
    /// <summary>
    /// This action represents the error page
    /// </summary>
    /// <param name="Message">Error message to be displayed (provided via querystring parameter - a design choice)</param>
    /// <returns></returns>
    public ActionResult Index(string Message)
    {
        // We choose to use the ViewBag to communicate the error message to the view
        ViewBag.Message = Message;
        return View();
    }

}

错误页面视图:

<!DOCTYPE html>

<html>
<head>
    <title>Error</title>
</head>
<body>

    <h2>My Error</h2>
    <p>@ViewBag.Message</p>
</body>
</html>

除了在 FilterConfig.cs 中禁用/删除 filters.Add(new HandleErrorAttribute()) 之外,不涉及其他任何内容

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //filters.Add(new HandleErrorAttribute()); // <== disable/remove
    }
}

虽然实现起来非常简单,但我在这种方法中看到的一个缺点是使用查询字符串将异常信息传递到目标错误页面。


D
DCShannon

我已经完成了所有设置,但在我们的暂存服务器上仍然看不到状态代码 500 的正确错误页面,尽管事实上在本地开发服务器上一切正常。

我从 Rick Strahl 那里找到了对我有帮助的 this blog post

我需要将 Response.TrySkipIisCustomErrors = true; 添加到我的自定义错误处理代码中。


@Shaun314 你的意思是你把代码放在哪里?在处理请求的操作中。您可以在该博客文章中看到示例。
A
ADM-IT

这是我的解决方案。在我看来,使用 [ExportModelStateToTempData] / [ImportModelStateFromTempData] 不舒服。

~/Views/Home/Error.cshtml:

@{
    ViewBag.Title = "Error";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Error</h2>
<hr/>

<div style="min-height: 400px;">

    @Html.ValidationMessage("Error")

    <br />
    <br />

    <button onclick="Error_goBack()" class="k-button">Go Back</button>
    <script>
        function Error_goBack() {
            window.history.back()
        }
    </script>

</div>

~/控制器/HomeController.sc:

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Error()
    {
        return this.View();
    }

    ...
}

~/Controllers/BaseController.sc:

public class BaseController : Controller
{
    public BaseController() { }

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is ViewResult)
        {
            if (filterContext.Controller.TempData.ContainsKey("Error"))
            {
                var modelState = filterContext.Controller.TempData["Error"] as ModelState;
                filterContext.Controller.ViewData.ModelState.Merge(new ModelStateDictionary() { new KeyValuePair<string, ModelState>("Error", modelState) });
                filterContext.Controller.TempData.Remove("Error");
            }
        }
        if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
        {
            if (filterContext.Controller.ViewData.ModelState.ContainsKey("Error"))
            {
                filterContext.Controller.TempData["Error"] = filterContext.Controller.ViewData.ModelState["Error"];
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

~/Controllers/MyController.sc:

public class MyController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Details(int id)
    {
        if (id != 5)
        {
            ModelState.AddModelError("Error", "Specified row does not exist.");
            return RedirectToAction("Error", "Home");
        }
        else
        {
            return View("Specified row exists.");
        }
    }
}

祝你项目成功;-)


R
Robert Hoffmann

您可以在不破解 global.cs、弄乱 HandleErrorAttribute、执行 Response.TrySkipIisCustomErrors、连接 Application_Error 或其他任何事情的情况下正常工作的错误:

在 system.web 中(只是通常,开/关)

<customErrors mode="On">
  <error redirect="/error/401" statusCode="401" />
  <error redirect="/error/500" statusCode="500" />
</customErrors>

并在 system.webServer

<httpErrors existingResponse="PassThrough" />

现在事情应该按预期运行,您可以使用 ErrorController 来显示您需要的任何内容。


如何模拟 IIS 引发的错误。无论是 500 还是 504。在 ASP.Net MVC 中做什么 - 5 代码来模拟来自 IIS 的异常,以便我可以测试我的自定义错误页面
@Unbreakable 临时更改您的代码以引发异常。
对我没有任何影响。如果出现异常或 404 not found 错误,我不会被带到我的自定义错误页面。
D
Dpk-Kumar

在 web.config 中添加如下 system.webserver 标签,

<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404"/>
  <remove statusCode="500"/>
  <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound"/>
  <error statusCode="500" responseMode="ExecuteURL"path="/Error/ErrorPage"/>
</httpErrors>

并添加一个控制器,

public class ErrorController : Controller
{
    //
    // GET: /Error/
    [GET("/Error/NotFound")]
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;

        return View();
    }

    [GET("/Error/ErrorPage")]
    public ActionResult ErrorPage()
    {
        Response.StatusCode = 500;

        return View();
    }
}

并加上他们尊重的观点,我想这肯定会奏效。

我从以下位置找到了这个解决方案:Neptune Century


波斯字符编码混乱
O
OrElse

看来我来晚了,但你最好也检查一下。

所以在 system.web 中用于缓存应用程序中的异常,例如 return HttpNotFound()

  <system.web>
    <customErrors mode="RemoteOnly">
      <error statusCode="404" redirect="/page-not-found" />
      <error statusCode="500" redirect="/internal-server-error" />
    </customErrors>
  </system.web>

并在 system.webServer 中用于捕获 IIS 捕获但未进入 asp.net 框架的错误

 <system.webServer>
    <httpErrors errorMode="DetailedLocalOnly">
      <remove statusCode="404"/>
      <error statusCode="404" path="/page-not-found" responseMode="Redirect"/>
      <remove statusCode="500"/>
      <error statusCode="500" path="/internal-server-error" responseMode="Redirect"/>
  </system.webServer>

在最后一个中,如果您担心客户端响应,请将 responseMode="Redirect" 更改为 responseMode="File" 并提供静态 html 文件,因为这将显示一个带有 200 响应代码的友好页面。


波斯字符编码混乱

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅