asp.net-mvc - ASP.NET MVC 应用程序自定义错误页面未显示在共享托管环境中

标签 asp.net-mvc error-handling global-asax shared-hosting

我在共享主机上部署的 ASP.NET MVC 应用程序上遇到自定义错误问题。我创建了一个 ErrorController 并将以下代码添加到 Global.asax 以捕获未处理的异常,记录它们,然后将控制权转移到 ErrorController 以显示自定义错误。此代码取自 here :

protected void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();
    Response.Clear();

    HttpException httpEx = ex as HttpException;
    RouteData routeData = new RouteData();
    routeData.Values.Add("controller", "Error");

    if (httpEx == null)
    {
        routeData.Values.Add("action", "Index");
    }
    else
    {
        switch (httpEx.GetHttpCode())
        {
            case 404:
                routeData.Values.Add("action", "HttpError404");
                break;
            case 500:
                routeData.Values.Add("action", "HttpError500");
                break;
            case 503:
                routeData.Values.Add("action", "HttpError503");
                break;
            default:
                routeData.Values.Add("action", "Index");
                break;
        }
    }

    ExceptionLogger.LogException(ex); // <- This is working. Errors get logged

    routeData.Values.Add("error", ex);
    Server.ClearError();
    IController controller = new ErrorController();
    // The next line doesn't seem to be working
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}

Application_Error 肯定会触发,因为日志记录工作正常,但我没有显示我的自定义错误页面,而是使用 Go Daddy 通用页面。从博客文章的标题中,上面的代码取自,我注意到它使用了 MVC 框架的 Release Candidate 2。 1.0 中是否有某些更改导致最后一行代码不起作用?像往常一样works great on my machine .

任何建议将不胜感激。

编辑:忘了提到我已经在 Web.config 中尝试了 customErrors 模式的所有 3 种可能性(关、开和 RemoteOnly)。无论此设置如何,结果都相同。

编辑 2:我也尝试过在 Controller 类上使用和不使用 [HandleError] 装饰。

更新:我已经弄清楚并修复了 404。 Go Daddy 主机控制中心的设置面板有一个部分,可以在其中控制 404 行为,默认设置是显示其通用页面,显然这会覆盖任何 Web.config 设置。所以我的自定义 404 页面现在按预期显示。但是,500 和 503 仍然无法正常工作。如果 Sql Server 抛出异常,我在 HomeController 中有代码来获取内容的静态文本版本,如下所示:
public ActionResult Index()
{
    CcmDataClassesDataContext dc = new CcmDataClassesDataContext();

    // This might generate an exception which will be handled in the OnException override
    HomeContent hc = dc.HomeContents.GetCurrentContent();

    ViewData["bodyId"] = "home";
    return View(hc);
}

protected override void OnException(ExceptionContext filterContext)
{
    // Only concerned here with SqlExceptions so an HTTP 503 message can
    // be displayed in the Home View. All others will bubble up to the
    // Global.asax.cs and be handled/logged there.
    System.Data.SqlClient.SqlException sqlEx =
        filterContext.Exception as System.Data.SqlClient.SqlException;
    if (sqlEx != null)
    {
        try
        {
            ExceptionLogger.LogException(sqlEx);
        }
        catch
        {
            // couldn't log exception, continue without crashing
        }

        ViewData["bodyId"] = "home";
        filterContext.ExceptionHandled = true;
        HomeContent hc = ContentHelper.GetStaticContent();
        if (hc == null)
        {
            // Couldn't get static content. Display friendly message on Home View.
            Response.StatusCode = 503;
            this.View("ContentError").ExecuteResult(this.ControllerContext);
        }
        else
        {
            // Pass the static content to the regular Home View
            this.View("Index", hc).ExecuteResult(this.ControllerContext);
        }
    }
}

这是尝试获取静态内容的代码:
public static HomeContent GetStaticContent()
{
    HomeContent hc;

    try
    {
        string path = Configuration.CcmConfigSection.Config.Content.PathToStaticContent;
        string fileText = File.ReadAllText(path);
        string regex = @"^[^#]([^\r\n]*)";
        MatchCollection matches = Regex.Matches(fileText, regex, RegexOptions.Multiline);
        hc = new HomeContent
            {
                ID = Convert.ToInt32(matches[0].Value),
                Title = matches[1].Value,
                DateAdded = DateTime.Parse(matches[2].Value),
                Body = matches[3].Value,
                IsCurrent = true
            };
    }
    catch (Exception ex)
    {
        try
        {
            ExceptionLogger.LogException(ex);
        }
        catch
        {
            // couldn't log exception, continue without crashing
        }
        hc = null;
    }

    return hc;
}

我已经验证,如果我更改连接字符串以生成 SqlException,代码会正确记录错误,然后抓取并显示静态内容。但是,如果我还更改 Web.config 中静态文本文件的路径以测试 503 版本的主 View ,我得到的是一个页面,除了“服务不可用”之外别无他物。就是这样。没有带有网站外观的自定义 503 消息。

有没有人对可能有帮助的代码改进有任何建议?将不同的 header 添加到 HttpResponse 是否有帮助?还是 Go Daddy 霸道地劫持了 503?

最佳答案

我找到了解决方案,而且非常简单。原来问题实际上出在IIS7中。在 Visual Studio 中调试此问题时,我看到了 HttpResponse 对象的一个​​我以前没有注意到的属性:

public bool TrySkipIisCustomErrors { get; set; }

这让我找到了离我最近的搜索引擎,它出现了 great blog post by Rick Strahl另一个在 angrypets.com以及 this question here on SO .这些链接比我能更好地解释血腥细节,但是 Rick 帖子中的这句话很好地捕捉到了它:

The real confusion here occurs because the error is trapped by ASP.NET, but then ultimately still handled by IIS which looks at the 500 status code and returns the stock IIS error page.



这种行为似乎也特定于集成模式下的 IIS7。来自 msdn :

When running in Classic mode in IIS 7.0 the TrySkipIisCustomErrors property default value is true. When running in Integrated mode, the TrySkipIisCustomErrors property default value is false.



所以基本上我最终要做的就是添加 Response.TrySkipIisCustomErrors = true;在任何设置 Response.StatusCode 的代码之后到 500 或 503,现在一切都按设计运行。

关于asp.net-mvc - ASP.NET MVC 应用程序自定义错误页面未显示在共享托管环境中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1706934/

相关文章:

asp.net-mvc - 我应该使用 EF 在存储库模式中实现 DTO 吗?

.net - ASP.NET MVC - IsAjaxRequest() 的实际含义是什么?

asp.net-mvc - EditorForModel - 使用 editorfor 时出现重复标签

python - 代码在命令提示符下逐行运行,但是当我整体运行文件时出现新问题

JSON .Net 错误地生成架构(类型为数组)

c - 检测 C 中的段错误

javascript - Express 中不清楚的错误处理

asp.net - Global.asax 未处理的异常

asp.net-mvc - asp.net mvc 并检查用户是否已登录

c# - Response.Redirect 在 Global.asax 中不起作用