23

我希望将所有401错误重定向到自定义错误页面。我最初在我的web.config中设置了以下条目。如何在Asp.Net Mvc 3中显示自定义错误页面?

<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,但没有无济于事。我尝试过使用组合<custom errors><httpErrors>但没有运气 - 标准错误或空白页仍然显示。

httpErrors部分看起来像这样在基于the link的那一刻起above SO question(我还发现另一个非常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文件,并修改<httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath"><httpErrors lockAttributes="allowAbsolutePathsWhenDelegated">根据来自iis.net的信息。在我的努力过程中,我也设法按照another SO question中所述的方法偶然发现了这个错误。

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

其他信息

下列控制器动作已经装饰了Authorise属性为特定用户。

[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"); 
} 
+0

我也想知道如何获得自定义错误显示(在我的情况下403错误) - 500错误工作正常... –

+0

作出一个小型图书馆,使这更容易。它是可用的:https://github.com/Buildstarted/Errlusion – Buildstarted

+1

只是想你可能有兴趣看到这[SO帖子](http://stackoverflow.com/questions/6308186/custom-errors-not-working-with - iisexpress) – CBRRacer

回答

10

我从来没有能够得到一个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); 
    } 

在ErrorsController:

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现在不在那里处理,但你可以很容易地添加它。

+1

感谢您的答复 - 但是我已经看到了这种方法,出于某种原因,它并没有吸引我。 – Ahmad

+1

@Ahmad我既不,但它的作品。 :)我发现试图使用web.config中的CustomErrors进行设置,这取决于引发错误的位置/方式,它并不总是有效。 – Tridus

+1

好的答案 - 除了我还会在Application_Error的块周围添加if(!HttpContext.Current.IsDebuggingEnabled),以便在调试时仍显示错误。 – NightOwl888

34

我使用以下步骤:

// 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"); 
      } 
     } 

AND:

// 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 -the最终步骤:

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

<customErrors mode="Off"/> 
+0

这似乎工作,异常是烦人的调试时Windows身份验证和我在服务器上测试时必须将httpErrors existingResponse =“PassThrough”添加到Web配置中。谢谢虽然.. –

+0

其投掷错误CS0151:开关表达式或案例标签必须是布尔型,字符型,字符串型,整数型,枚举型或相应的可以为null的类型..help plz ?? – codespider

+0

这只对调试时适用于我。我怎样才能让它在服务器上工作?我仍然可以看到服务器上的默认错误页面。 IIS有错误页面设置模式=关闭。 – Soenhay

9

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

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

所有你需要做的是在config打开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。例如,以显示View命名为MyArgumentErrorArgumentException类型的异常发生时,你可以使用:

[ControllerAction,ExceptionHandler("MyArgumentError",typeof(ArgumentException))] 
public void Index() 
{ 
    // some code that could throw ArgumentExcepton 
} 

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

+2

工作问题是,IIS Express已经处理了其他状态代码(不是500),所以你建议并不总是工作(取决于IIS设置)。 IIS只显示它自己的页面,而我们从来没有在asp中看到它。 –

+0

的确,这只是IIS配置,但这是一个不同的问题。 MVC错误处理应该如上所述完成。 – TheCodeKing

0

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

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

而且我有一个错误控制器,包含所有必需的操作。我不认为MVC可以直接调用.aspx页面。

+0

它可以和aspx页面一起工作,事实上,如果你使用的是重写模式,那么你必须使用静态内容文件(而不是动作) –

相关问题