Обработайте ошибку с помощью NLog и попробуйте Catch

Я регистрирую ошибки в своих действиях, используя NLog для хранения ошибок с дополнительной информацией, например:

using NLog;

private static Logger _logger = LogManager.GetCurrentClassLogger();

public virtual ActionResult Edit(Client client)
{
  try
  {
        // FORCE ERROR
        var x = 0;

        x /= x;

        return RedirectToAction(MVC.Client.Index());
  }
  catch (Exception e)
  {
    _logger.Error("[Error in ClientController.Edit - id: " + client.Id + " - Error: " + e.Message + "]");
  }
}

И у меня настроена обработка ошибок в Web.config:

<customErrors mode="On" />

Но меня не перенаправляют на Error.cshtml, когда я выполняю действие (страница остается на том же месте), почему?

Могу ли я использовать Elmah, чтобы сделать то же самое? (регистрация дополнительной информации, такой как идентификатор клиента)


person Patrick    schedule 05.12.2015    source источник
comment
Очень просто: вы не будете перенаправлены на error.cshtml, потому что для конвейера ASP.NET ошибка не произошла. Вам придется повторно создать исключение или создать новое.   -  person Camilo Terevinto    schedule 05.12.2015
comment
Привет спасибо, есть ли смысл это делать? или можно по другому?   -  person Patrick    schedule 05.12.2015
comment
Да, это стандартное ведение журнала в ASP.NET, если я правильно помню.   -  person Camilo Terevinto    schedule 05.12.2015
comment
Может быть, я мог бы перенаправить на представление ошибок вместо того, чтобы повторно выдавать ошибку, нет?   -  person Patrick    schedule 05.12.2015
comment
Это еще один вариант. Но если вы перенаправите, вы получите код состояния Redirect; если вы выдаете ошибку, вы получите 50x (точное число не помню, я думаю, что это 500, но слишком сонно)   -  person Camilo Terevinto    schedule 05.12.2015
comment
Да, но на данный момент я получил подробную информацию об ошибке по электронной почте, поэтому я могу продолжить отправку отзыва пользователю.   -  person Patrick    schedule 05.12.2015
comment
@Patrick... Вы можете создать собственный атрибут, который будет обрабатывать ваши ошибки в одном месте. Если интересно, выложу пример.   -  person Big Daddy    schedule 07.12.2015
comment
@BigDaddy Привет, спасибо. И смогу ли я регистрировать дополнительную информацию о запросе действия, такую ​​как идентификатор клиента?   -  person Patrick    schedule 07.12.2015


Ответы (3)


Во-первых, большинство людей решают эту ошибку, не перехватывая исключение. Таким образом, исключение распространяется на ASP.NET, который отображает веб-страницу "500 Internal Error", и вся соответствующая информация регистрируется.

  • Если ваш сервер настроен для работы, на странице ошибки будет просто указано «произошла ошибка, подробности были зарегистрированы».

  • Если сервер настроен для разработки, вы получите знаменитую желтую страницу с типом исключения, сообщением и трассировкой стека.

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

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


Теперь я нахожу это очень неуклюжим, потому что мне не нравится вручную искать исходные файлы, упомянутые на желтой странице, и вручную переходить к указанным номерам строк. Жёлтая страница мне практически ни к чему, с тем же успехом она могла бы просто сказать «произошла ошибка, плачь мне рекой, нах-нах-нах». Я не читаю желтую страницу.

Вместо этого мне нравится регистрировать исключения самостоятельно, и мой регистратор начинает каждую строку с full-path-to-source-filename(line):, так что каждая строка в журнале отладки в Visual Studio кликабельна, и нажатие на строку автоматически открывает правильный исходный файл, и прокручивается до той строки, которая выдала сообщение журнала. Если вам нужна эта роскошь, то идите вперед и перехватите исключение, но сразу после регистрации исключения вы должны повторно создать его, чтобы все шло своим чередом.

Поправка

Вот некоторая информация, которая была добавлена ​​в комментарии:

Итак, вы можете сделать следующее:

try
{
   ...
}
catch (Exception e)
{
    log( "information" );
    throw; //special syntax which preserves original stack trace
}

Or

try
{
   ...
}
catch (Exception e)
{
    throw new Exception( "information", e ); //also preserves original stack trace
}

Не делайте не этого: catch( Exception e ) { log( "information" ); throw e; }, потому что при этом теряется исходная информация о трассировке стека e.

person Mike Nakis    schedule 11.12.2015
comment
Привет спасибо! И как вы отлавливаете ошибки в производственной среде? Я пытаюсь создать ярлык, поэтому, когда я получаю электронное письмо с ошибкой от NLog, я точно знаю, какой clientId, например, мне нужно отлаживать. - person Patrick; 14.12.2015
comment
Я полагаю, что если вы решите поймать, зарегистрировать и перебросить, то вы, вероятно, можете включить clientid в журналируемый текст или вы можете сделать что-нибудь еще, что вы хотите сделать вместо регистрации. Например, вы можете добавить идентификатор клиента в какую-либо таблицу в базе данных. Но все это не связано с тем, будете ли вы перенаправлять на страницу с ошибкой. Я предлагаю, чтобы после того, как вы записали любую информацию, которую вам нужно записать, вместо того, чтобы выполнять собственное перенаправление, вы должны просто перебросить и позволить серверу обрабатывать исключение в зависимости от того, как оно было настроено. - person Mike Nakis; 14.12.2015
comment
И повторное выбрасывание ошибки, по вашему мнению, является хорошей практикой? или вы поступили бы иначе? Как я могу сбросить ошибку в моем случае? Спасибо - person Patrick; 14.12.2015
comment
Да, повторная выдача ошибки — это очень хорошая практика, и C# даже поддерживает для этого специальный синтаксис. Проверьте это: stackoverflow.com/questions/881473/ - person Mike Nakis; 14.12.2015
comment
Так что я просто бросаю; после регистрации ошибки, правильно? Что вы думаете о комментарии Дункана? И да, try...catch не делает ничего полезного (кроме потери стека вызовов - так что на самом деле это еще хуже - если только вы по какой-то причине не хотите раскрывать эту информацию). ? - person Patrick; 14.12.2015
comment
Да кидайте после логирования ошибки. Если вас действительно волнует трассировка стека, включенная в исходное исключение (а вы обычно это делаете), Дункан предлагает создать новое исключение и передать ему старое исключение в качестве аргумента. - person Mike Nakis; 14.12.2015
comment
Спасибо Майк за вашу помощь! Я проверил, что ваша помощь верна;) Спасибо. - person Patrick; 14.12.2015

В вашем коде ошибка возникает в части разделения (x/=x), поэтому не выполняется строка перенаправления (индексная страница) и не выполняется переход к части перехвата, выполняющей регистратор. Вы также должны определить перенаправление на Error.cshtml в части перехвата.

Примечание. При использовании блока try catch ошибка не возникает на уровне ASP.NET, что приводит к отсутствию перенаправления на страницу Error.cshtml

using NLog;

private static Logger _logger = LogManager.GetCurrentClassLogger();

public virtual ActionResult Edit(Client client)
{
  try
  {
        // FORCE ERROR
        var x = 0;

        x /= x; /// error occur here

        return RedirectToAction(MVC.Client.Index()); /// no execution of this line
  }
  catch (Exception e)
  {
    _logger.Error("[Error in ClientController.Edit - id: " + client.Id + " - Error: " + e.Message + "]");
    /// add redirect link here 
     return RedirectToAction(MVC.Client.Error()); /// this is needed since the catch block execute mean no error at ASP.net level resulting no redirect to default error page

  }
}
person Dipitak    schedule 09.12.2015
comment
Привет, спасибо, это решение, которое у меня есть прямо сейчас в проекте, но оно пришло с проблемой, я никогда не получаю в среде разработки Желтую страницу смерти, потому что я всегда перенаправляю. Мне всегда нужно проверять электронную почту или журнал, чтобы получить подробную информацию об ошибке :( - person Patrick; 09.12.2015

Это упростит обработку исключений и позволит более лаконично управлять процессом. Создайте такой атрибут:

 public class HandleExceptionAttribute : System.Web.Mvc.HandleErrorAttribute
    {
        // Pass in necessary data, etc
        private string _data;
        public string Data
        {
            get { return _data; }
            set { _data = value; }
        }

        public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
        {            
            // Logging code here
            // Do something with the passed-in properties (Data in this code)
            // Use the filterContext to retrieve all sorts of info about the request
            // Direct the user

            base.OnException(filterContext);
        }
    }

Теперь вы можете использовать его на уровне контроллера или метода с таким атрибутом:

[HandleException(Data="SomeValue", View="Error")]

Или зарегистрируйте его глобально (global.asax) следующим образом:

GlobalFilters.Filters.Add(new HandleExceptionAttribute());
person Big Daddy    schedule 07.12.2015
comment
Привет спасибо! Но это означает, что я могу регистрировать только одно значение, и если я хочу регистрировать 2 значения, мне нужен другой атрибут? - person Patrick; 07.12.2015
comment
На основе построения строки на основе нескольких значений? - person Patrick; 08.12.2015
comment
Вы можете зарегистрировать что-либо из запроса или создать дополнительные свойства для пользовательского атрибута исключения и гидратировать их из аннотации. - person Big Daddy; 08.12.2015
comment
И SomeValue может получить доступ к значениям внутри действия, например, у clientId, который проходит, есть параметр? - person Patrick; 08.12.2015