Страницы пользовательских ошибок приложения ASP.NET MVC не отображаются в среде общего хостинга - PullRequest
14 голосов
/ 10 ноября 2009

У меня проблема с пользовательскими ошибками в приложении ASP.NET MVC, которое я развернул на своем общем хосте. Я создал ErrorController и добавил следующий код в Global.asax, чтобы перехватывать необработанные исключения, регистрировать их, а затем передавать управление в ErrorController для отображения пользовательских ошибок. Этот код взят из здесь :

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 Go Daddy. Из заголовка блога, взятого выше, взят код, я заметил, что он использует Release Candidate 2 платформы MVC. Что-то изменилось в 1.0, из-за чего последняя строка кода не работает? Как обычно, прекрасно работает на моей машине .

Любые предложения будут с благодарностью.

Редактировать: забыл упомянуть, что я попробовал все 3 возможности для режима customErrors в Web.config (Off, On и RemoteOnly). Одинаковые результаты независимо от этого параметра.

Редактировать 2: И я также попробовал это с и без украшения [HandleError] на классах Controller.

Обновление: я разобрался и исправил 404. В Центре управления хостингом Go Daddy есть раздел панели «Настройки», в котором можно управлять поведением 404 и по умолчанию показывать их общую страницу, что, очевидно, переопределяет любые настройки Web.config. Таким образом, моя пользовательская страница 404 теперь отображается так, как задумано. Однако 500 и 503 все еще не работают. У меня есть код в HomeController для захвата статической текстовой версии контента, если Sql Server выдает исключение следующим образом:

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-версию Home View, вместо этого я получу страницу, на которой нет ничего, кроме «служба недоступна». Вот и все. Нет пользовательского сообщения 503 с внешним видом сайта.

У кого-нибудь есть предложения по улучшению кода, которые могут помочь? Поможет ли это добавить разные заголовки в HttpResponse? Или Go Daddy безжалостно угоняет 503-е?

Ответы [ 2 ]

29 голосов
/ 12 ноября 2009

Я нашел решение, и оно невероятно просто. Оказывается, проблема была на самом деле в IIS7. При отладке этой проблемы в Visual Studio я обнаружил свойство объекта HttpResponse, которое раньше не замечал:

public bool TrySkipIisCustomErrors { get; set; }

Это привело меня к моей ближайшей поисковой системе, которая обнаружила отличное сообщение в блоге Рика Строла и еще одну на angrypets.com , а также этот вопрос здесь, на SO . Эти ссылки объясняют кровавые подробности гораздо лучше, чем я, но эта цитата из поста Рика отражает это довольно хорошо:

Настоящая путаница здесь происходит, потому что ошибка поймана в ловушку ASP.NET, но в конечном итоге все еще обрабатывается IIS, который смотрит на 500 код состояния и возвращает страницу ошибки IIS на складе.

Также кажется, что это поведение характерно для IIS7 в интегрированном режиме. От MSDN :

При работе в классическом режиме в IIS 7.0 TrySkipIisCustomErrors свойство по умолчанию имеет значение true. При работе в интегрированном режиме Свойство TrySkipIisCustomErrors по умолчанию имеет значение false.

Так что, по сути, все, что мне пришлось сделать, это добавить Response.TrySkipIisCustomErrors = true; сразу после любого кода, который устанавливает Response.StatusCode на 500 или 503, и все теперь работает как задумано.

0 голосов
/ 11 ноября 2009

Я размещаю сайт ASP.NET MVC на GoDaddy, а также столкнулся с проблемами, связанными с пользовательскими страницами ошибок. Методом проб и ошибок я обнаружил, что GoDaddy перехватывает ошибки на уровне HTTP.

Например, любая страница, которая возвратила код состояния HTTP 404, вызывала переход к пользовательской странице ошибки GoDaddy. В конце концов я изменил свои пользовательские страницы ошибок, чтобы вернуть статус 200, и проблема, связанная с 404, ушла. Мой HTML был таким же, только статус HTTP, необходимый для изменения.

Я, по общему признанию, никогда не пытался сделать то же самое с 503 ответами о состоянии, но возможно, что то же самое смягчение может работать. Если вы перешли от возврата статуса 503 к возвращению статуса 200, проблема исчезнет?

Обратите внимание, что, если вы сделаете этот обходной путь, вы захотите запретить поисковым системам индексировать ваши страницы ошибок, которые однажды вернут статус 200, будет неразличимым (с точки зрения поисковой системы) с обычной страницы. Поэтому обязательно добавьте тег META ROBOTS для предотвращения индексации страниц с ошибками, например,

<META NAME="ROBOTS" CONTENT="NOINDEX">

Недостатком этого подхода может быть то, что ваша страница может быть удалена из Google, что, безусловно, не очень хорошая вещь!

ОБНОВЛЕНИЕ: Таким образом, кроме того, вы также можете определить, является ли пользовательский агент сканером или нет, и если это сканер, возвращает 503, а если он не сканер, возвращает 200. См. это сообщение в блоге для получения информации о том, как обнаружить сканеры. Да, я знаю, что возвращать различный контент сканерам и пользователям - это SEO-нет-нет, но я сделал это на нескольких сайтах без каких-либо негативных последствий, поэтому я не уверен, насколько это серьезная проблема.

Выполнение обоих подходов (META ROBOTS и обнаружение ботов) может быть вашим лучшим выбором в случае, если какие-то чудаковцы проскользнут через детектор ботов.

...