Ошибка приложения не срабатывает, когда customerrors = " On"



у меня есть код global.asax файла Application_Error событие, которое выполняется при возникновении ошибки и отправляет детали ошибки самому себе.



void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();

if (error.Message != "Not Found")
{
// Send email here...
}

}


это отлично работает, когда я запускаю его в Visual Studio, однако, когда я публикую на нашем живом сервере Application_Error событие не срабатывает.



после некоторого тестирования я могу получить Application_Error стрельба, когда я установил customErrors="Off", однако установка его обратно в customErrors="On" останавливает событие от стрельбы снова.



может кто-нибудь подскажет почему Application_Error не будет стрелять, когда customErrors включены в web.config?

647   9  

9 ответов:

обновление
Поскольку этот ответ действительно дает решение, я не буду его редактировать, но я нашел гораздо более чистый способ решения этой проблемы. Смотрите мой другой ответ для сведения...

Оригинальный Ответ:
Я понял, почему Application_Error() метод не вызывается...

глобальные.асакс.cs

public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute()); // this line is the culprit
    }
...
}

по умолчанию (при создании нового проекта) приложение MVC имеет какая-то логика в . Эта логика используется для сопоставления маршрутов и регистрации фильтров. По умолчанию, он регистрирует только один фильтр:. Когда customErrors включены (или через удаленные запросы, когда он установлен в RemoteOnly), атрибут HandleErrorAttribute сообщает MVC искать представление ошибок и никогда не вызывает Application_Error() метод. Я не мог найти документацию об этом, но это объясняется в этот ответ на programmers.stackexchange.com.

получить Ошибка приложения() метод, который вызывается для каждый необработанное исключение, просто удалите строку, которая регистрирует фильтр HandleErrorAttribute.

теперь проблема: как настроить customErrors, чтобы получить то, что вы хотите...

в разделе customErrors по умолчанию установлено значение redirectMode="ResponseRedirect". Вы также можете указать атрибут defaultRedirect как маршрут MVC. Я создал ErrorController, который был очень прост и изменил мою сеть.config, чтобы выглядеть этот...

web.конфигурации

<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
  <error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>

проблема с этим решением заключается в том, что он выполняет перенаправление 302 на ваши URL-адреса ошибок, а затем эти страницы отвечают кодом состояния 200. Это приводит к индексации Google страниц ошибок, что плохо. Он также не очень соответствует спецификации HTTP. То, что я хотел сделать, это не перенаправлять, а перезаписывать исходный ответ с помощью моих пользовательских представлений ошибок.

я пытался изменить redirectMode="ResponseRewrite". К сожалению, этот параметр не поддерживает маршруты MVC, только статические HTML-страницы или ASPX. Сначала я попытался использовать статическую HTML-страницу, но код ответа был все еще 200, но, по крайней мере, он не перенаправлял. Затем я получил идею от ответ...

я решил отказаться от MVC для обработки ошибок. Я создал Error.aspx и PageNotFound.aspx. Эти страницы были очень простыми, но в них была одна часть магии...

<script type="text/C#" runat="server">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
    }
</script>

этот блок сообщает странице быть подается с правильным кодом состояния. Из грубых, на странице найденной.aspx-страницы, я использовал HttpStatusCode.NotFound вместо. Я изменил свою паутину.конфигурация должна выглядеть так...

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
  <error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>

все работало отлично!

резюме:

  • удалить строку: filters.Add(new HandleErrorAttribute());
  • использовать Application_Error() метод регистрации исключений
  • используйте customErrors с ResponseRewrite, указывая на страницы ASPX
  • сделать страницы ASPX ответственными за их собственные коды состояния ответа

есть несколько недостатков, которые я заметил с этим решением.

  • страницы ASPX не могут делиться разметкой с шаблонами Razor, мне пришлось переписать стандартную разметку верхнего и нижнего колонтитулов нашего сайта для последовательного внешнего вида.
  • The *.aspx страницы могут быть доступны непосредственно, нажав их URL

есть обходные пути для этих проблем, но я не был достаточно обеспокоен им делать любую дополнительную работу.

я надеюсь, что это помогает всем!

Я решил эту проблему, создав ExceptionFilter и регистрируя ошибку там вместо Application_Error. Все, что вам нужно сделать, это добавить вызов в In в RegisterGlobalFilters

log4netExceptionFilter.cs

using System
using System.Web.Mvc;

public class log4netExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        Exception ex = context.Exception;
        if (!(ex is HttpException)) //ignore "file not found"
        {
            //Log error here
        }
    }
}

глобальные.асакс.cs

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new log4netExceptionFilter()); //must be before HandleErrorAttribute
    filters.Add(new HandleErrorAttribute());
}

я нашел статьи который описывает гораздо более чистый способ создания пользовательских страниц ошибок в веб-приложении MVC3, который не препятствует возможности регистрировать исключения.

решение заключается в использовании <httpErrors> элемент .

Я настроил мой Web.конфигурации вот так...

<httpErrors errorMode="DetailedLocalOnly" existingResponse="Replace">
  <remove statusCode="404" subStatusCode="-1" />
  <remove statusCode="500" subStatusCode="-1" />
  <error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL" />
  <error statusCode="500" path="/Error" responseMode="ExecuteURL" />
</httpErrors>

я тоже настроен customErrors иметь mode="Off" (как предлагается в статье).

что делает ответы, переопределенные действиями ErrorController. Вот этот контроллер:

public class ErrorController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult NotFound()
    {
        return View();
    }
}

представления очень прямолинейны, я просто использовал стандартный синтаксис Razor для создания страниц.

этого должно быть достаточно для использования пользовательских страниц ошибок с MVC.

Я также нуждался в регистрации исключений, поэтому я украл Марка использования пользовательского фильтра исключений...

public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext exceptionContext)
    {
        var exception = exceptionContext.Exception;
        var request = exceptionContext.HttpContext.Request;
        // log stuff
    }
}

последнее, что вам нужно так это зарегистрируйте фильтр исключений в своем глобальные.асакс.cs file:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new ExceptionPublisherExceptionFilter());
    filters.Add(new HandleErrorAttribute());
}

это похоже на гораздо более чистое решение, чем мой предыдущий ответ, и работает так же хорошо, насколько я могу судить. Мне это нравится, особенно потому, что я не чувствовал, что борюсь против структуры MVC; это решение фактически использует его!

в случае ASP.NET MVC5 использовать

public class ExceptionPublisherExceptionFilter : IExceptionFilter
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();
        public void OnException(ExceptionContext exceptionContext)
        {
            var exception = exceptionContext.Exception;
            var request = exceptionContext.HttpContext.Request;
            // HttpException httpException = exception as HttpException;
            // Log this exception with your logger
            _logger.Error(exception.Message);
        }
    }

вы можете найти его в FilterConfig.cs of .

Мне нравится ответ Марка с ExceptionFilter, но другой вариант, если у вас есть все ваши контроллеры, производные от одного и того же базового контроллера, - это просто переопределить OnException в вашем базовом контроллере. Вы можете сделать свой журнал и по электронной почте там. Это имеет то преимущество, что вы можете использовать любые зависимости, которые вы уже ввели в свой базовый контроллер с вашим контейнером IoC.

вы все еще можете использовать свой IoC с IExceptionFilter, но это немного сложнее настройка Привязок.

насколько я знаю, вы передаете управление на страницу, указанную в параметре url, и ваше уведомление о событии будет сидеть здесь, а не Application_Error

<customErrors defaultRedirect="myErrorPage.aspx"
              mode="On">
</customErrors>

много информации можно найти здесь:http://support.microsoft.com/kb/306355

чтобы обойти это, я в конечном итоге оставил customerrors отключенным и обрабатывал все ошибки из события Application_Error в global.асакс. Это немного сложно с MVC, поскольку я не хотел возвращать перенаправление 301, я хотел вернуть подходящие коды ошибок. Более подробную информацию можно посмотреть в моем блоге по адресу http://www.wduffy.co.uk/blog/using-application_error-in-asp-net-mvcs-global-asax-to-handle-errors/ но окончательный код приведен ниже...

void Application_Error(object sender, EventArgs e)
{
    var error = Server.GetLastError();
    var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500;

    if (code != 404)
    {
            // Generate email with error details and send to administrator
    }

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

    string path = Request.Path;
    Context.RewritePath(string.Format("~/Errors/Http{0}", code), false);
    IHttpHandler httpHandler = new MvcHttpHandler();
    httpHandler.ProcessRequest(Context);
    Context.RewritePath(path, false);
}

а вот это контроллер

public class ErrorsController : Controller
{

    [HttpGet]
    public ActionResult Http404(string source)
    {
            Response.StatusCode = 404;
            return View();
    }

    [HttpGet]
    public ActionResult Http500(string source)
    {
            Response.StatusCode = 500;
            return View();
    }

}

эта запись в блоге помогла мне:

http://asp-net.vexedlogic.com/2011/04/23/asp-net-maximum-request-length-exceeded/

если вы используете IIS 7.0 или выше, вы можете изменить свой веб.конфигурационный файл для обработки слишком больших запросов. Есть некоторые предостережения, но вот пример:

<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="1048576" />
    </requestFiltering>
  </security>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" subStatusCode="13" />
    <error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="/UploadTooLarge.htm" responseMode="Redirect" />
  </httpErrors>
</system.webServer>

есть дополнительные сведения об этих элементах файла конфигурации здесь:

http://www.iis.net/ConfigReference/system.webServer/security/requestFiltering/requestLimits

код состояния 404.13 определяется как"слишком большая длина содержимого". Одна важная вещь, чтобы отметить, что maxAllowedContentLength задается в байтах. Это отличается от maxRequestLength настройки вы найдете в разделе <system.web> раздел, который указан в килобайтах.

<system.web>
  <httpRuntime maxRequestLength="10240" />
</system.web>

также обратите внимание, что path атрибут должен быть абсолютным путем, когда responseMode и Redirect, поэтому добавьте имя виртуального каталога, если это необходимо. Информативные ответы Джесси Уэбба показывают, как это сделать с responseMode="ExecuteURL", и я думаю, что этот подход тоже будет работать хорошо.

этот подход не работает, если вы разрабатываете с помощью сервера разработки Visual Studio (Cassini, веб-сервер, интегрированный в Visual Studio). Я предполагаю, что это будет работать в IIS Express, но я не проверял это.

у меня была та же проблема, где Application_Error() не получил удар. Я перепробовал все, пока, наконец, не шагнул через то, что происходило. У меня был какой-то пользовательский код в событии ELMAH, который добавлял JSON к электронной почте, которую он отправляет, и там была нулевая ошибка!

исправление внутренней ошибки позволило коду перейти к Application_Error() событие, как ожидалось.

Comments

    Ничего не найдено.