Ошибка приложения не срабатывает, когда 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?
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.csof .
Мне нравится ответ Марка с 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