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

Asp.net mvc 3 asp.net MVC3上的自定义错误页,asp.net-mvc-3,error-handling,Asp.net Mvc 3,Error Handling,我正在开发一个基于MVC3的网站,我正在寻找处理错误的解决方案,并为每种错误提供自定义视图。因此,假设我有一个“错误”控制器,其中他的主要操作是“索引”(通用错误页面),并且该控制器将有多个操作来处理用户可能会看到的错误,如“Handle500”或“HandleActionNotFound” 因此,网站上可能发生的每一个错误都可以由这个“错误”控制器来处理(例如:找不到“控制器”或“操作”、500、404、dbException等) 我使用站点地图文件来定义网站路径(而不是路线) 这个问题已经得

我正在开发一个基于MVC3的网站,我正在寻找处理错误的解决方案,并为每种错误提供自定义视图。因此,假设我有一个“错误”控制器,其中他的主要操作是“索引”(通用错误页面),并且该控制器将有多个操作来处理用户可能会看到的错误,如“Handle500”或“HandleActionNotFound”

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

我使用站点地图文件来定义网站路径(而不是路线)

这个问题已经得到了回答,这是对Gweebz的回答

我的最终应用错误方法如下:

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

下面是一个如何处理自定义错误的示例。我定义了一个
ErrorsController
,其中包含处理不同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");
    }
}
然后我在
Global.asax
中订阅
Application\u Error
,并调用此控制器:

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

这里有更多关于如何使用MVC创建自定义错误页面的文章。

您可以通过实现Jeff Atwood的,对http状态代码稍加修改,来显示具有正确http状态代码的用户友好错误页面。它在没有任何重定向的情况下工作。虽然代码来自2004年(!),但它与MVC配合得很好。它可以完全在web.config中配置,而无需对MVC项目源代码进行任何更改

返回原始HTTP状态而不是
200
状态所需的修改如中所述

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

标题中的“
”。。。
Private _exhttppexas HttpException=无
'在公共子句柄异常的顶部(ByVal ex作为异常)。。。
HttpContext.Current.Response.StatusCode=500
如果TypeOf ex是HttpException,那么
_exHttpEx=CType(ex,HttpException)
HttpContext.Current.Response.StatusCode=\u exhttppex.GetHttpCode()
如果结束

您也可以在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>

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

由于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
        }
    }
然后在配置中放置
,这样部署是安全的,当您需要测试自定义错误页面时,您可以将其设置为
,以便验证它是否有效


注意:您还需要检查
HttpContext.Current
是否为空,因为
应用程序_Start
中的异常仍将使用此方法,尽管不会有活动上下文。

我使用的是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);
    }
}
}

只是一张小纸条。因为我想在每个ActionResult的每个案例(404500等)中呈现一个视图,所以我返回了一个视图。然而,我尝试捕捉了应用程序的错误内容,并在失败的情况下返回了一个静态HTML页面。(如果有人愿意,我可以发布代码)我无法在MVC3上使用此解决方案渲染razor视图。例如,返回视图(模型)仅获得一个空白屏幕。添加了TrySkipIisCustomErrors以修复集成IIS7。请参见@ajbeaven,
Execute
是在
IController
界面中定义的方法。这不可能得到保护。更仔细地查看我的代码:
IController errorscoontroller=newerrorscoontroller()
并注意调用
Execute
方法的
errorscocontroller
变量的类型。它属于
IController
类型,因此绝对没有任何东西阻止您调用此方法。顺便说一句,
Execute
在控制器类中以及在MVC 3中受到保护,因此在这方面没有变化。通过明确指定响应的内容类型来修复:
response.ContentType=“text/html”web.config中应该有哪些设置来支持此操作?很可能您不包括任何httperrors设置?有一些很好的提示,比如IE在512字节以下时不会显示你的错误页面。你对Darin的解决方案有什么问题?你没有描述你遇到的问题,并给出了一个竞争性的答案。