如何在 Asp.Net Mvc 3 中显示自定义错误页面?

Posted

技术标签:

【中文标题】如何在 Asp.Net Mvc 3 中显示自定义错误页面?【英文标题】:How do I display custom error pages in Asp.Net Mvc 3? 【发布时间】:2011-10-07 15:57:14 【问题描述】:

我希望将所有 401 错误重定向到自定义错误页面。我最初在我的 web.config 中设置了以下条目。

<customErrors defaultRedirect="ErrorPage.aspx" mode="On">
  <error statusCode="401" redirect="~/Views/Shared/AccessDenied.aspx" />
</customErrors>

使用 IIS Express 时,我收到了常见的 IIS Express 401 错误页面。

如果我不使用 IIS Express,则会返回空白页。使用谷歌浏览器的网络选项卡检查响应,我看到当页面为空白时,标题中返回 401 状态

到目前为止,我尝试使用来自this SO answer 的建议,因为我使用的是 IIS Express,但无济于事。我尝试使用&lt;custom errors&gt;&lt;httpErrors&gt; 的组合,但没有成功 - 仍然显示标准错误或空白页。

httpErrors 部分目前基于above SO question 中的the link 看起来像这样(我还发现了另一个非常promising answer 但是没有运气 - 空白回复)

<system.webServer>
  <httpErrors  errorMode="DetailedLocalOnly" existingResponse="PassThrough" >
    <remove statusCode="401"  />
    <error statusCode="401" path="/Views/Shared/AccessDenied.htm" />
  </httpErrors>

 <!-- 
 <httpErrors  errorMode="Custom" 
             existingResponse="PassThrough" 
             defaultResponseMode="ExecuteURL">
      <remove statusCode="401"  />
  <error statusCode="401" path="~/Views/Shared/AccessDenied.htm" 
         responseMode="File" />
 </httpErrors>
 -->
</system.webServer>

我什至修改了applicationhost.config 文件,并根据iis.net 的信息将&lt;httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath"&gt; 修改为&lt;httpErrors lockAttributes="allowAbsolutePathsWhenDelegated"&gt;。在我努力的过程中,我还设法偶然发现了这个错误,如another SO question 中所述。

其他信息

以下控制器操作已被特定用户的Authorize 属性修饰。

[HttpGet]
[Authorize(Users = "domain\\userXYZ")]
public ActionResult Edit() 

   return GetSettings();


[HttpPost]
[Authorize(Users = "domain\\userXYZ")]
public ActionResult Edit(ConfigurationModel model, IList<Shift> shifts)

    var temp = model;
    model.ConfiguredShifts = shifts;
    EsgConsole config = new EsgConsole();

    config.UpdateConfiguration(model.ToDictionary());
    return RedirectToAction("Index");

【问题讨论】:

我还想知道如何显示自定义错误(在我的情况下是 403 错误)- 500 错误工作正常... 制作了一个小型库来简化此操作。可用:github.com/Buildstarted/Errlusion 只是觉得你可能有兴趣看到这个SO post @CBRRacer 该帖子实际上解决了我遇到的问题,不确定 OP。此外,这个问题的答案都没有提到所需的所有配置选项,因此很难奖励赏金...... 获得了赏金,但没有一个答案是我想要的,@CBRRacer 的链接中有更好的答案 【参考方案1】:

我使用这些步骤:

// in Global.asax.cs:
        protected void Application_Error(object sender, EventArgs e) 

            var ex = Server.GetLastError().GetBaseException();

            Server.ClearError();
            var routeData = new RouteData();
            routeData.Values.Add("controller", "Error");
            routeData.Values.Add("action", "Index");

            if (ex.GetType() == typeof(HttpException)) 
                var httpException = (HttpException)ex;
                var code = httpException.GetHttpCode();
                routeData.Values.Add("status", code);
             else 
                routeData.Values.Add("status", 500);
            

            routeData.Values.Add("error", ex);

            IController errorController = new Kavand.Web.Controllers.ErrorController();
            errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
        

        protected void Application_EndRequest(object sender, EventArgs e) 
            if (Context.Response.StatusCode == 401)  // this is important, because the 401 is not an error by default!!!
                throw new HttpException(401, "You are not authorised");
            
        

与:

// in Error Controller:
    public class ErrorController : Controller 

        public ActionResult  Index(int status, Exception error) 
            Response.StatusCode = status;
            return View(status);
        

        protected override void Dispose(bool disposing) 
            base.Dispose(disposing);
        
    

和错误文件夹中的索引视图:

@* in ~/Views/Error/Index.cshtml: *@

@model Int32    
@
    Layout = null;
    
<!DOCTYPE html>    
<html>
<head>
    <title>Kavand | Error</title>
</head>
<body>
    <div>
        There was an error with your request. The error is:<br />
        <p style=" color: Red;">
        @switch (Model) 
            case 401: 
                    <span>Your message goes here...</span>
                
                break;
            case 403: 
                    <span>Your message goes here...</span>
                
                break;
            case 404: 
                    <span>Your message goes here...</span>
                
                break;
            case 500: 
                    <span>Your message goes here...</span>
                
                break;
            //and more cases for more error-codes...
            default: 
                    <span>Unknown error!!!</span>
                
                break;
        
        </p>
    </div>
</body>
</html>

AND - 最后一步:

<!-- in web.config: -->

<customErrors mode="Off"/>

【讨论】:

这似乎有效,在使用 Windows 身份验证进行调试时异常很烦人,并且在服务器上进行测试时,我确实必须将 httpErrors existingResponse="PassThrough" 添加到 Web 配置中。不过还是谢谢你.. 它的抛出错误 CS0151: A switch expression or case label must be a bool, char, string, integer, enum, or对应的可空类型..help plz?? 这只在调试时对我有用。我怎样才能让它在服务器上工作?我仍然在服务器上看到默认错误页面。 IIS 的错误页面设置模式 = 关闭。 我不知道。可能是你的服务器的配置不同。我在许多网站上使用它大约 3 年。它工作得很好。对不起):【参考方案2】:

我永远无法让 web.config 和 MVC 中的 CustomErrors 一起玩得很好,所以我放弃了。我这样做了。

在 global.asax 中:

protected void Application_Error()
    
        var exception = Server.GetLastError();
        var httpException = exception as HttpException;
        Response.Clear();
        Server.ClearError();
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "General";
        routeData.Values["exception"] = exception;
        Response.StatusCode = 500;
        if (httpException != null)
        
            Response.StatusCode = httpException.GetHttpCode();
            switch (Response.StatusCode)
            
                case 403:
                    routeData.Values["action"] = "Http403";
                    break;
                case 404:
                    routeData.Values["action"] = "Http404";
                    break;
            
        
        // Avoid IIS7 getting in the middle
        Response.TrySkipIisCustomErrors = true;
        IController errorsController = new GNB.LG.StrategicPlanning.Website.Controllers.ErrorsController();
        HttpContextWrapper wrapper = new HttpContextWrapper(Context);
        var rc = new RequestContext(wrapper, routeData);
        errorsController.Execute(rc);
    

在错误控制器中:

public class ErrorsController

    public ActionResult General(Exception exception)
    
        // log the error here
        return View(exception);
    

    public ActionResult Http404()
    
        return View("404");
    

    public ActionResult Http403()
    
        return View("403");
    

在 web.config 中:

<customErrors mode="Off" />

无论在何处或如何创建错误,这对我都有效。 401 目前没有在那里处理,但您可以很容易地添加它。

【讨论】:

感谢您的回答 - 但是我已经看到了这种方法,由于某种原因它对我没有吸引力。 @Ahmad 我也不是,但它有效。 :) 我发现尝试在 web.config 中使用 CustomErrors 进行设置,这取决于引发错误的位置/方式,它并不总是有效。 很好的答案 - 除了我还会在 Application_Error 的块周围添加一个 if (!HttpContext.Current.IsDebuggingEnabled) 以便调试时仍然显示错误。 +1,非常有用且有效的答案,几乎可以解决所有类型的错误(我搜索了一周来控制 web.config 中的错误,但没有找到完整的解决方案)【参考方案3】:

也许我遗漏了一些东西,但 MVC 有一个使用自定义错误的默认全局 ErrorHandlerAttribute。这解释得很好here。

public static void RegisterGlobalFilters(GlobalFilterCollection filters)

    filters.Add(new HandleErrorAttribute());

您需要做的就是在配置中打开custom errors,然后设置自定义错误重定向,最好是静态HTML 文件(以防应用出现错误)。

<customErrors mode="On" defaultRedirect="errors.htm">
    <error statusCode="404" redirect="errors404.htm"/>
</customErrors>

如果您愿意,也可以指向自定义Controller 以显示错误。在下面的示例中,我刚刚使用默认路由到名为ErrorController,并使用名为Index 的操作和名为id 的字符串参数(以接收错误代码)。您当然可以使用您想要的任何路由。您的示例不起作用,因为您试图直接链接到Views 目录而不通过Controller。 MVC .NET 不直接向Views 文件夹提供请求。

<customErrors mode="On" defaultRedirect="/error/index/500">
    <error statusCode="404" redirect="/error/index/404"/>
</customErrors>

ErrorHandlerAttribute 还可以与Controllers/Actions 一起广泛使用,以将错误重定向到与Controller 相关的命名Views。例如,当出现ArgumentException 类型的异常时,要显示名为MyArgumentErrorView,您可以使用:

[ControllerAction,ExceptionHandler("MyArgumentError",typeof(ArgumentException))]
public void Index()

   // some code that could throw ArgumentExcepton

当然另一种选择是更新Shared 中的股票Error 页面。

【讨论】:

问题是 IIS express 已经处理了那些其他状态代码(不是 500),所以你的建议并不总是有效(取决于 IIS 设置)。 IIS 只是显示它自己的页面,我们从来没有通过 asp 中的视图。 没错,这只是 IIS 配置,但这是一个不同的问题。 MVC 错误处理应该像上面那样完成。【参考方案4】:

查看 web.config 的第一部分,您将直接指向一个 .aspx 页面。当我设置错误页面时,我直接指向控制器和操作。例如:

<customErrors mode="On" defaultRedirect="~/Error/UhOh">
  <error statusCode="404" redirect="~/Error/NotFound" />
  <error statusCode="403" redirect="~/Error/AccessDenied" />
</customErrors>

我有一个包含所有必需操作的错误控制器。我认为 MVC 在直接调用 .aspx 页面时表现不佳。

【讨论】:

它确实适用于 aspx 页面,事实上如果您使用的是重写模式,那么您必须使用静态内容文件(而不是操作)

以上是关于如何在 Asp.Net Mvc 3 中显示自定义错误页面?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.Net MVC:如何自定义验证消息显示

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

如何在 ASP.NET MVC 3 中自定义不显眼的验证以匹配我的风格?

未记录 ELMAH 和 ASP.NET MVC 自定义错误

如何在 ASP NET MVC 中自定义不显眼的验证 JQuery 消息?

如何在 ASP.Net MVC 5 视图中获取 ApplicationUser 的自定义属性值?