asp.net-mvc ASP.NET MVC 5 自定义错误页面
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23565098/
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
ASP.NET MVC 5 Custom Error Page
提问by Haider
I am using a custom authorize attribute in a ASP.NET MVC 5application like following:
我在ASP.NET MVC 5应用程序中使用自定义授权属性,如下所示:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext context)
{
if (context.HttpContext.Request.IsAuthenticated)
{
context.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
}
else
{
base.HandleUnauthorizedRequest(context);
}
}
}
In system.websection of my web.config I mentioned error paths like:
在system.web我的 web.config 部分中,我提到了错误路径,例如:
<system.web>
<customErrors mode="On" defaultRedirect="/Error/Error">
<error statusCode="403" redirect="/Error/NoPermissions"/>
</customErrors>
</system.web>
But I am never redirected to my custom error page at /Error/NoPermissions. Instead the browser display the general error page saying "HTTP Error 403.0 - Forbidden".
但我从来没有被重定向到我的自定义错误页面/Error/NoPermissions。相反,浏览器会显示一般错误页面,上面写着“HTTP 错误 403.0 - 禁止”。
采纳答案by Haider
Thanks everyone, but problem is not with 403 code. Actually the problem was with the way i was trying to return 403. I just changed my code to throw an HttpExceptioninstead of returning the HttpStatusCodeResultand every things works now. I can return any HTTP status code by throwing HttpExceptionexception and my customErrorsconfiguration catches all of them. May be HttpStatusCodeResultis not doing the exact job I expected it to do.
谢谢大家,但问题不在于 403 代码。实际上,问题出在我试图返回 403 的方式上。我只是将代码更改为抛出一个HttpException而不是返回HttpStatusCodeResult并且现在一切正常。我可以通过抛出HttpException异常返回任何 HTTP 状态代码,我的customErrors配置会捕获所有这些状态代码。可能HttpStatusCodeResult没有做我期望它做的确切工作。
I just replaced
我刚换了
context.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
with
和
throw new HttpException((int)System.Net.HttpStatusCode.Forbidden, "Forbidden");
That's it.
就是这样。
Happy coding.
快乐编码。
回答by ubik404
[1]: Remove all 'customErrors' & 'httpErrors' from Web.config
[1]:从 Web.config 中删除所有“customErrors”和“httpErrors”
[2]: Check 'App_Start/FilterConfig.cs' looks like this:
[2]:检查“App_Start/FilterConfig.cs”看起来像这样:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
[3]: in 'Global.asax' add this method:
[3]:在“Global.asax”中添加这个方法:
public void Application_Error(Object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Server.ClearError();
var routeData = new RouteData();
routeData.Values.Add("controller", "ErrorPage");
routeData.Values.Add("action", "Error");
routeData.Values.Add("exception", exception);
if (exception.GetType() == typeof(HttpException))
{
routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
}
else
{
routeData.Values.Add("statusCode", 500);
}
Response.TrySkipIisCustomErrors = true;
IController controller = new ErrorPageController();
controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
Response.End();
}
[4]: Add 'Controllers/ErrorPageController.cs'
[4]:添加'Controllers/ErrorPageController.cs'
public class ErrorPageController : Controller
{
public ActionResult Error(int statusCode, Exception exception)
{
Response.StatusCode = statusCode;
ViewBag.StatusCode = statusCode + " Error";
return View();
}
}
[5]: in 'Views/Shared/Error.cshtml'
[5]:在“视图/共享/Error.cshtml”中
@model System.Web.Mvc.HandleErrorInfo
@{
ViewBag.Title = (!String.IsNullOrEmpty(ViewBag.StatusCode)) ? ViewBag.StatusCode : "500 Error";
}
<h1 class="error">@(!String.IsNullOrEmpty(ViewBag.StatusCode) ? ViewBag.StatusCode : "500 Error"):</h1>
//@Model.ActionName
//@Model.ControllerName
//@Model.Exception.Message
//@Model.Exception.StackTrace
:D
:D
回答by Dush
I also had this issue. Code in the OP's question is perfectly working except the custom error code in <system.web>section in the web.configfile. To fix the issue what I need to do was add the following code to <system.webServer>. Note that ‘webserver'instead of ‘web'.
我也有这个问题。除了文件<system.web>部分中的自定义错误代码外,OP 问题中的代码完全正常工作web.config。为了解决这个问题,我需要做的是将以下代码添加到<system.webServer>. 请注意,‘webserver'而不是‘web'.
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="403" />
<error statusCode="403" responseMode="ExecuteURL" path="/Error/UnAuthorized" />
</httpErrors>
If someone is using following environment, here is the complete solution:
如果有人使用以下环境,这里是完整的解决方案:
The Environment:
环境:
- Visual Studio 2013 Update 4
- Microsoft .NET Framework 4.5.1 with ASP.NET MVC 5
- Project: ASP.NET Web Application with MVC & Authentication: Individual User Account template
- Visual Studio 2013 更新 4
- 带有 ASP.NET MVC 5 的 Microsoft .NET Framework 4.5.1
- 项目:具有 MVC 和身份验证的 ASP.NET Web 应用程序:个人用户帐户模板
Custom Attribute class:
自定义属性类:
Add the following class to your web site's default namespace. The reason explained here in the accepted answer Stack Overflow question:Why does AuthorizeAttribute redirect to the login page for authentication and authorization failures?
将以下类添加到您网站的默认命名空间。在接受的答案堆栈溢出问题中解释了原因:为什么 AuthorizeAttribute 重定向到登录页面以进行身份验证和授权失败?
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
Then add the following code the web.configfile
然后在web.config文件中添加以下代码
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="403" />
<error statusCode="403" responseMode="ExecuteURL" path="/Error/UnAuthorized" />
</httpErrors>
</system.webServer>
Following article explain more about this: ASP.NET MVC: Improving the Authorize Attribute (403 Forbidden)
以下文章对此进行了更多解释:ASP.NET MVC:改进授权属性(403 Forbidden)
And httpErrors in web.configsection in this article: Demystifying ASP.NET MVC 5 Error Pages and Error Logging
以及本文中 web.config部分中的httpErrors:Demystifying ASP.NET MVC 5 Error Pages and Error Logging
Then add the ErrorController.csto Controllers folder
然后将ErrorController.cs添加到 Controllers 文件夹
public class ErrorController : Controller
{
// GET: UnAuthorized
public ActionResult UnAuthorized()
{
return View();
}
public ActionResult Error()
{
return View();
}
}
Then add a UnAuthorized.cshtmlto View/Shared folder
然后添加一个UnAuthorized.cshtml到 View/Shared 文件夹
@{
ViewBag.Title = "Your Request Unauthorized !"; //Customise as required
}
<h2>@ViewBag.Title.</h2>
This will show customised error page instead of browser generated error page.
这将显示自定义错误页面而不是浏览器生成的错误页面。
Also note that for the above environment, it is not required to comment the code inside RegisterGlobalFiltersmethod added by the template as suggested in one of the answers.
另请注意,对于上述环境,不需要RegisterGlobalFilters按照其中一个答案的建议对模板添加的方法内的代码进行注释。
Please note that I just cut and paste code from my working project therefore I used Unauthorizedinstead OP's NoPermissionsin the above code.
请注意,我只是从我的工作项目中剪切和粘贴代码,因此我在上面的代码中使用了UnauthorizedOP NoPermissions。
回答by dustinmoris
since I ran into a very similar issue I wanted to shed more light on it.
因为我遇到了一个非常相似的问题,所以我想更清楚地了解它。
customErrors will only capture actual http exceptions thrown in your ASP.NET application. The HttpStatusCodeResult doesn't throw an exception though. It just writes a response with the according status code, which makes more sense in your example.
customErrors 将只捕获在您的 ASP.NET 应用程序中抛出的实际 http 异常。不过 HttpStatusCodeResult 不会抛出异常。它只是使用相应的状态代码编写响应,这在您的示例中更有意义。
If you are running on IIS 7.0 or higher you should be using httpErrors now, as this will show you custom error pages in all cases. This is an IIS level setting.
如果您在 IIS 7.0 或更高版本上运行,您现在应该使用 httpErrors,因为这将在所有情况下向您显示自定义错误页面。这是一个 IIS 级别设置。
I wrote a whole blog post about this to explain the differences: http://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging
我写了一篇关于此的完整博客文章来解释差异:http: //dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging
回答by ryanulit
Update
更新
You only need to do that special redirect for 403 errors. All other 500 errors should take effect through your defaultRedirect="/Error/Error"setting in customErrors. However, you need to remove or comment out the HandleErrorAttribute registration in the App_Start/FilterConfig.cs file for custom errors to actually work. Otherwise, that attribute will redirect all errors to the Error.cshtml file in the Views/Shared directory.
您只需要针对 403 错误执行该特殊重定向。所有其他 500 错误应通过您defaultRedirect="/Error/Error"在customErrors. 但是,您需要删除或注释掉 App_Start/FilterConfig.cs 文件中的 HandleErrorAttribute 注册,以使自定义错误真正起作用。否则,该属性会将所有错误重定向到 Views/Shared 目录中的 Error.cshtml 文件。
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// remove this line below
//filters.Add(new HandleErrorAttribute());
}
}
Original Answer
原答案
As far as I know, you cannot use customErrors in the web.config to handle 403 errors for some reason. I feel your pain as it seems like something that should be as simple as the code you already have, but apparently 403 errors are treated as a web server concern.
据我所知,由于某种原因,您不能在 web.config 中使用 customErrors 来处理 403 错误。我感到您的痛苦,因为它看起来应该像您已有的代码一样简单,但显然 403 错误被视为 Web 服务器问题。
What you can do instead is just redirect the user to your desired "NoPermissions" page like this:
您可以做的只是将用户重定向到您想要的“NoPermissions”页面,如下所示:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext context)
{
if (context.HttpContext.Request.IsAuthenticated)
{
context.Result = new RedirectToRouteResult(new RouteValueDictionary(new
{
action = "NoPermissions",
controller = "Error",
area = ""
}));
}
else
{
base.HandleUnauthorizedRequest(context);
}
}
}
The request will have a 200 status code instead of a 403, but if you can live with that, this is an easy workaround.
该请求将有一个 200 状态代码而不是 403,但如果您可以接受,这是一个简单的解决方法。
Here is a similar SO question for more info: Returning custom errors.
这是一个类似的 SO 问题以获取更多信息:Returning custom errors。
Also, this article explains how to go the IIS route: http://kitsula.com/Article/MVC-Custom-Error-Pages
另外,这篇文章解释了如何走 IIS 路线:http: //kitsula.com/Article/MVC-Custom-Error-Pages
回答by NMeneses
These seem to be complicated workarounds. Here is basically all you need to do to get your custom error pages (CEP) working:
这些似乎是复杂的解决方法。基本上,您需要做的就是让您的自定义错误页面 (CEP) 正常工作:
- Add an Error Controller in your controllers folder.
- Inside your Error Controller annotate the classwith
[HandleError]. - For each error you want to display a CEP for, create an
ActionResultmethod. - Create a View for each CEP inside ~/Views/Shared/Errorfolder, and customize it how you like. (The Error folder should have been created when you created your controller. If it did not, you will need to create the Error folder first.)
- Open the web.config file at the root level*Note: there are two (2) web.config files. One in your Views folder, the other at the Root level of your application.
- Inside
<system.web>, add<customError mode="On" defaultRedirect="~/Error/Error"> - For each error code you have a CEP for; add
<error statusCode="[StatusCode]" redirect="~/Error/[CEP Name]">. You can leave off the file extension.
- 在您的控制器文件夹中添加一个错误控制器。
- 里面让错误控制器注释类用
[HandleError]。 - 对于要为其显示 CEP 的每个错误,创建一个
ActionResult方法。 - 为 ~/Views/Shared/Error文件夹中的每个 CEP 创建一个视图,并根据需要对其进行自定义。(在您创建控制器时应该已经创建了 Error 文件夹。如果没有,您需要先创建 Error 文件夹。)
- 在根级别打开web.config 文件*注意:有两 (2) 个 web.config 文件。一个在您的 Views 文件夹中,另一个在您的应用程序的根级别。
- 在里面
<system.web>,添加<customError mode="On" defaultRedirect="~/Error/Error"> - 对于每个错误代码,您都有一个 CEP;添加
<error statusCode="[StatusCode]" redirect="~/Error/[CEP Name]">. 您可以不使用文件扩展名。
Controller Example:
控制器示例:
namespace NAMESPACE_Name.Controllers
{
[HandleError]
public class ErrorController : Controller
{
// GET: Error
public ActionResult BadRequest()
{
return View();
}
public ActionResult Error()
{
return View();
}
public ActionResult Forbidden()
{
return View();
}
public ActionResult InternalServerError()
{
return View();
}
public ActionResult NotFound()
{
return View();
}
public ActionResult NotImplemented()
{
return View();
}
public ActionResult ServerBusyOrDown()
{
return View();
}
public ActionResult ServerUnavailable()
{
return View();
}
public ActionResult Timeout()
{
return View();
}
public ActionResult Unauthorized()
{
return View();
}
}
}
View Example:
查看示例:
@{
Layout = "~/Views/Shared/_FullWidthLayout.cshtml";
ViewBag.Title = "404 Error";
}
<div class="opensans margin-sides text-center">
<div class="text-center">
<h1 class="text-normal">Uh oh! Something went wrong!</h1>
<div class="img-container text-center">
<div class="centered">
<h1 class="bold">404 - Not Found</h1>
</div>
<img class="img text-center" src="~/Images/BackgroundImg.png" style="opacity: 0.15;" />
</div>
<p class="text-left">
This is usually the result of a broken link, a web page that has been moved or deleted, or a mistyped URL.
<ol class="text-left">
<li>Check the URL you entered in the address bar for typos,</li>
<li>If the address you entered is correct, the problem is on our end.</li>
<li>Please check back later as the resource you requested could be getting worked on,</li>
<li>However, if this continues for the resource you requested, please submit a <a href="mailto:EmailAddress?subject=Website%20Error">trouble ticket</a>.</li>
</ol>
</p>
</div>
</div>
Web.Config Example:
Web.Config 示例:
<customErrors mode="On" defaultRedirect="~/Error/Error">
<!--The defaultRedirect page will display for any error not listed below.-->
<error statusCode="400" redirect="~/Error/BadRequest"/>
<error statusCode="401" redirect="~/Error/Unauthorized"/>
<error statusCode="403" redirect="~/Error/Forbidden"/>
<error statusCode="404" redirect="~/Error/NotFound"/>
<error statusCode="408" redirect="~/Error/Timeout"/>
<error statusCode="500" redirect="~/Error/InternalServerError"/>
<error statusCode="501" redirect="~/Error/NotImplemented"/>
<error statusCode="502" redirect="~/Error/ServerUnavailable"/>
<error statusCode="503" redirect="~/Error/ServerBusyOrDown"/>
</customErrors>
That's it! Step-by-step solution to a problem that really shouldn't be a problem!
就是这样!逐步解决一个真正不应该成为问题的问题!

