asp.net MVC3上的自定义错误页


144

我正在开发一个MVC3基本网站,并且正在寻找一种解决方案,用于处理错误并为每种错误呈现自定义视图。因此,假设我有一个“错误”控制器,其主要动作是“索引”(通用错误页面),并且该控制器将针对用户可能会出现的错误(例如“ Handle500”或“ HandleActionNotFound”)执行更多操作。

因此,此“错误”控制器可以处理网站上可能发生的每个错误(例如:找不到“控制器”或“操作”,500、404,dbException等)。

我正在使用Sitemap文件定义网站路径(而不是路线)。

该问题已经回答,这是对Gweebz的回复

我最后的applicaiton_error方法如下:

protected void Application_Error() {
//while my project is running in debug mode
if (HttpContext.Current.IsDebuggingEnabled && WebConfigurationManager.AppSettings["EnableCustomErrorPage"].Equals("false"))
{
    Log.Logger.Error("unhandled exception: ", Server.GetLastError());
}
else
{
    try
    {
        var exception = Server.GetLastError();

        Log.Logger.Error("unhandled exception: ", exception);

        Response.Clear();
        Server.ClearError();
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "General";
        routeData.Values["exception"] = exception;

        IController errorsController = new ErrorsController();
        var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
        errorsController.Execute(rc);
    }
    catch (Exception e)
    {
        //if Error controller failed for same reason, we will display static HTML error page
        Log.Logger.Fatal("failed to display error page, fallback to HTML error: ", e);
        Response.TransmitFile("~/error.html");
    }
}
}

web.config中应包含哪些设置以支持此设置?大概您不包括任何httperrors设置吗?
philbird

forums.asp.net/p/1782402/4894514.aspx/…有一些不错的技巧,例如IE低于512字节时IE不会显示您的错误页面
RickAndMSFT 2012年

Answers:


201

这是我如何处理自定义错误的示例。我定义一个ErrorsControllerwith操作来处理不同的HTTP错误:

public class ErrorsController : Controller
{
    public ActionResult General(Exception exception)
    {
        return Content("General failure", "text/plain");
    }

    public ActionResult Http404()
    {
        return Content("Not found", "text/plain");
    }

    public ActionResult Http403()
    {
        return Content("Forbidden", "text/plain");
    }
}

然后我订阅Application_Errorin 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;
        }
    }

    IController errorsController = new ErrorsController();
    var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
    errorsController.Execute(rc);
}

4
只是一点笔记。由于我想在每个ActionResult上分别渲染一个视图(404、500等),因此我返回了一个View。但是,我尝试绕过Application_Error内容,并且在失败的情况下返回了静态HTML页面。(如果有人愿意,我可以发布代码)
John Louros

4
我无法在MVC3上使用此解决方案来呈现剃刀视图。例如,返回View(model)仅得到一个空白屏幕。
Extrakun 2011年

2
添加了TrySkipIisCustomErrors来针对集成的IIS7进行修复。见stackoverflow.com/questions/1706934/...
帕维尔·萨瓦拉

1
@ajbeaven Execute是在IController接口中定义的方法。这可能无法得到保护。请更仔细地看一下我的代码:IController errorsController = new ErrorsController();并注意在其errorsController上调用Execute方法的变量的类型。它是类型的,IController因此绝对没有阻止您调用此方法的方法。顺便说一下Execute,MVC 3中的Controller类也受到了保护,因此在这方面没有任何变化。
Darin Dimitrov

2
通过明确指定响应的内容类型来解决:Response.ContentType = "text/html";
ajbeaven 2013年


6

您也可以在Web.Config文件中执行此操作。这是在IIS 7.5中工作的示例。

     <system.webServer>
          <httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File">
                <remove statusCode="502" subStatusCode="-1" />
                <remove statusCode="501" subStatusCode="-1" />
                <remove statusCode="412" subStatusCode="-1" />
                <remove statusCode="406" subStatusCode="-1" />
                <remove statusCode="405" subStatusCode="-1" />
                <remove statusCode="404" subStatusCode="-1" />
                <remove statusCode="403" subStatusCode="-1" />
                <remove statusCode="401" subStatusCode="-1" />
                <remove statusCode="500" subStatusCode="-1" />
                <error statusCode="500" path="/notfound.html" responseMode="ExecuteURL" />
                <error statusCode="401" prefixLanguageFilePath="" path="/500.html" responseMode="ExecuteURL" />
                <error statusCode="403" prefixLanguageFilePath="" path="/403.html" responseMode="ExecuteURL" />
                <error statusCode="404" prefixLanguageFilePath="" path="/404.html" responseMode="ExecuteURL" />
                <error statusCode="405" prefixLanguageFilePath="" path="/405.html" responseMode="ExecuteURL" />
                <error statusCode="406" prefixLanguageFilePath="" path="/406.html" responseMode="ExecuteURL" />
                <error statusCode="412" prefixLanguageFilePath="" path="/412.html" responseMode="ExecuteURL" />
                <error statusCode="501" prefixLanguageFilePath="" path="/501.html" responseMode="ExecuteURL" />
                <error statusCode="502" prefixLanguageFilePath="" path="/genericerror.html" responseMode="ExecuteURL" />
           </httpErrors>
</system.webServer>

3

我看到您为添加了配置值,EnableCustomErrorPage并且还在检查IsDebuggingEnabled以确定是否运行错误处理。

由于<customErrors/>ASP.NET中已经有一个配置(正是为了这个目的),所以最简单的说一下:

    protected void Application_Error()
    {
        if (HttpContext.Current == null) 
        {
                // errors in Application_Start will end up here                
        }
        else if (HttpContext.Current.IsCustomErrorEnabled)
        {
                // custom exception handling
        }
    }

然后,在配置中放入<customErrors mode="RemoteOnly" />可以安全地部署的配置,并且当您需要测试自定义错误页面时,将其设置为<customErrors mode="On" />可以验证其是否有效。

请注意,您还需要检查是否HttpContext.Current为null,因为Application_Start即使没有活动的上下文,该方法中的异常仍然会存在。


2

您可以通过实施Jeff Atwood的用户友好异常处理模块(对HTTP状态代码稍作修改)来显示具有正确的http状态代码的用户友好错误页面。它无需任何重定向即可工作。尽管代码来自2004(!),但它与MVC兼容。可以完全在您的web.config中对其进行配置,而无需更改MVC项目源代码。

此相关论坛帖子中200介绍了返回原始HTTP状态而不是状态所需的修改。

基本上,在Handler.vb中,您可以添加以下内容:

' In the header...
Private _exHttpEx As HttpException = Nothing

' At the top of Public Sub HandleException(ByVal ex As Exception)...
HttpContext.Current.Response.StatusCode = 500
If TypeOf ex Is HttpException Then
    _exHttpEx = CType(ex, HttpException)
    HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode()
End If

0

我正在使用MVC 4.5,但Darin解决方案存在问题。注意:Darin的解决方案非常出色,我用它来提出我的解决方案。这是我修改后的解决方案:

protected void Application_Error(object sender, EventArgs e)
{           
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.StatusCode = httpException.GetHttpCode();

Response.Clear();
Server.ClearError();


if (httpException != null)
{
    var httpContext = HttpContext.Current;

    httpContext.RewritePath("/Errors/InternalError", false);

    // MVC 3 running on IIS 7+
    if (HttpRuntime.UsingIntegratedPipeline)
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.Server.TransferRequest("/Errors/Http403", true);
                break;
            case 404:
                httpContext.Server.TransferRequest("/Errors/Http404", true);
                break;
            default:
                httpContext.Server.TransferRequest("/Errors/InternalError", true);
                break;
        }
    }
    else
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.RewritePath(string.Format("/Errors/Http403", true));
                break;
            case 404:
                httpContext.RewritePath(string.Format("/Errors/Http404", true));
                break;
            default:
                httpContext.RewritePath(string.Format("/Errors/InternalError", true));
                break;
        }

        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest(httpContext);
    }
}
}

2
您对Darin解决方案有什么问题?
肯尼·埃维特

您没有描述所遇到的问题导致答案相互竞争。
ivanjonas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.