Простой способ отловить все необработанные исключения в C # .NET - PullRequest
29 голосов
/ 17 ноября 2008

У меня есть сайт, построенный на C # .NET, который имеет тенденцию генерировать довольно устойчивый поток тайм-аутов SQL от различных пользовательских элементов управления, и я хочу легко вставить некоторый код, чтобы перехватить все необработанные исключения и отправить их во что-то, что может их регистрировать и отобразить дружественное сообщение для пользователя.

Как мне при минимальных усилиях перехватить все необработанные исключения?

этот вопрос , кажется, говорит, что это невозможно, но это не имеет смысла для меня (и это касается .NET 1.1 в приложениях для Windows):

Ответы [ 13 ]

26 голосов
/ 17 ноября 2008

Все необработанные исключения окончательно прошли через Application_Error в global.asax. Итак, чтобы дать общее сообщение об исключении или выполнить операции регистрации, см. Application_Error .

16 голосов
/ 17 ноября 2008

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

14 голосов
/ 17 ноября 2008

Используйте метод Application_Error в вашем файле Global.asax. Внутри вашей реализации метода Application_Error вызовите Server.GetLastError (), запишите подробности исключения, возвращенного Server.GetLastError (), как вам угодно.

, например

void Application_Error(object sender, EventArgs e) 
{ 
    // Code that runs when an unhandled error occurs
    log4net.ILog log = log4net.LogManager.GetLogger(typeof(object));
    using (log4net.NDC.Push(this.User.Identity.Name))
    {
        log.Fatal("Unhandled Exception", Server.GetLastError());
    }
}

Не обращайте слишком много внимания на вещи из log4net, Server.GetLastError () - самый полезный бит, регистрируйте детали, как вам удобно.

8 голосов
/ 17 ноября 2008

Проект ELMAH звучит достойно попробовать, его список функций включает:

ELMAH (Модули регистрации ошибок и Обработчики) - ошибка приложения лесозаготовительный объект, который полностью подключаемый. Это может быть добавлено динамически к работающему веб-приложению ASP.NET, или даже все веб-приложения ASP.NET на машине, без необходимости повторная компиляция или повторное развертывание.

  • Регистрация почти всех необработанных исключений.
  • Веб-страница для удаленного просмотра всего журнала перекодированных исключений.
  • Веб-страница для удаленного просмотра полной информации о любом из зарегистрированных исключение.
  • Во многих случаях вы можете просмотреть исходный желтый экран смерти, который ASP.NET создан для данного исключение, даже в режиме customErrors выключен.
  • Уведомление по электронной почте о каждой ошибке в момент ее возникновения.
  • RSS-лента последних 15 ошибок из журнала.
  • Количество реализаций резервного хранилища для журнала

Подробнее об использовании ELMAH от dotnetslackers

7 голосов
/ 17 ноября 2008

Вы можете подписаться на событие AppDomain.CurrentDomain.UnhandledException.

3 голосов
/ 17 ноября 2008

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

2 голосов
/ 17 ноября 2008

Вы имеете в виду обработку его во всех потоках, в том числе созданных сторонним кодом? В «известных» потоках просто ловите Exception на вершине стека.

1 голос
/ 29 июля 2009

Один короткий ответ заключается в использовании (анонимных) методов делегата с общим кодом обработки при вызове делегата.

Справочная информация : Если вы нацелились на слабые места или у вас есть какой-то стандартный код обработки ошибок, вам необходимо универсально применять его к определенному классу проблем, и вы не хотите писать ту же попытку. .catch для каждого местоположения вызова (например, обновление определенного элемента управления на каждой странице и т. д.).

Пример из практики : болевая точка - это веб-формы и сохранение данных в базе данных. У нас есть элемент управления, который отображает сохраненный статус для пользователя, и мы хотели, чтобы на каждой странице был общий код обработки ошибок, а также общее отображение без повторного копирования-вставки-повторного использования. Кроме того, каждая страница по-своему выполняла свои функции, поэтому единственной действительно распространенной частью кода была обработка ошибок и отображение.

Теперь, до того, как сработали, это не заменит слой доступа к данным и код доступа к данным. Это все еще предполагается, что существует хорошее разделение по уровням и т. Д. Этот код специфичен для уровня пользовательского интерфейса, что позволяет нам писать чистый код пользовательского интерфейса и не повторяться. Мы убеждены в том, что не нужно отменять исключения, но некоторые исключения не должны требовать, чтобы пользователь получил страницу с общей ошибкой и потерял свою работу. Будет время ожидания sql, серверы выйдут из строя, взаимоблокировки и т. Д.

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

// normal form code.
private void Save()
{
    // you can do stuff before and after. normal scoping rules apply
    saveControl.InvokeSave(
        delegate
        {
            // everywhere the save control is used, this code is different
            // but the class of errors and the stage we are catching them at
            // is the same
            DataContext.SomeStoredProcedure();
            DataContext.SomeOtherStoredProcedure();
            DataContext.SubmitChanges();
        });
}

В самом SaveControl есть такой метод:

public delegate void SaveControlDelegate();

public void InvokeSave(SaveControlDelegate saveControlDelegate)
{        
    // I've changed the code from our code. 
    // You'll have to make up your own logic.
    // this just gives an idea of common handling.
    retryButton.Visible = false;
    try
    {
        saveControlDelegate.Invoke();
    }
    catch (SqlTimeoutException ex)
    {
        // perform other logic here.
        statusLabel.Text = "The server took too long to respond.";
        retryButton.Visible = true;
        LogSqlTimeoutOnSave(ex);
    }
    // catch other exceptions as necessary. i.e.
    // detect deadlocks
    catch (Exception ex)
    {
        statusLabel.Text = "An unknown Error occurred";
        LogGenericExceptionOnSave(ex);
    }
    SetSavedStatus();
}

  • Есть и другие способы достижения этого (например, общий базовый класс, интерфейсы), но в нашем случае это было наилучшим образом.
  • Это не замена замечательному инструменту, такому как Elmah , для регистрации всех необработанных исключений. Это целенаправленный подход к обработке определенных исключений стандартным способом.
1 голос
/ 29 июля 2009

Ошибки тайм-аута обычно возникают, если вы принудительно не закрываете sqlconnections.

так что если у вас было

try {
    conn.Open();
    cmd.ExecuteReader();
    conn.Close();
} catch (SqlException ex) {
    //do whatever
}

Если что-то пойдет не так с этим ExecuteReader, ваше соединение не будет закрыто. Всегда добавляйте блок finally.

try {
    conn.Open();
    cmd.ExecuteReader();
    conn.Close();
} catch (SqlException ex) {
    //do whatever
} finally {
    if(conn.State != ConnectionState.Closed)
       conn.Close();
}
1 голос
/ 17 ноября 2008

Эта проблема решается двумя частями:

Определение

Это то, что вы делаете, когда, наконец, ловится исключение, а не обязательно, где оно выдается. Таким образом, исключение на этом этапе должно иметь достаточно контекстной информации, чтобы вы могли определить, в чем проблема

Обработка

Для обработки вы можете а) добавить HttpModeule. Увидеть http://www.eggheadcafe.com/articles/20060305.asp Я бы предложил этот подход только тогда, когда нет абсолютно никакой контекстной информации и может возникнуть проблема с IIS / aspnet, иначе говоря, для катастрофических ситуаций

b) Создайте абстрактный класс с именем AbstractBasePage, который является производным от класса Page, и все ваши классы codebehind являются производными от AbstractBasePage

AbstractBasePage может реализовать этот делегат Page.Error, так что все исключения, которые распространяются через n-уровневую архитектуру, могут быть обнаружены здесь (и, возможно, зарегистрированы)

Я бы предложил эту причину для того типа исключений, о которых вы говорите (SQlException), поскольку для вас достаточно контекстной информации, чтобы определить, что это был тайм-аут и предпринять возможные действия. Это действие может включать перенаправление пользователя на пользовательскую страницу ошибки с соответствующим сообщением для каждого типа исключений (Sql, webservice, тайм-ауты асинхронных вызовов и т. Д.).

Спасибо РВЗ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...