Вложенный Try / Catch - PullRequest
       8

Вложенный Try / Catch

18 голосов
/ 22 февраля 2010

Имеет ли вложенный Try / Catch сигнал, что вы не кодируете чисто? Я удивляюсь, потому что в моем улове я вызываю другой метод, и если это не удается, я получаю еще одну ошибку во время выполнения, поэтому у меня возникает соблазн обернуть эти вызовы в улове еще одной попыткой / уловом. Интересно, нормально ли это делать?

, например

    catch (Exception ex)
    {
        transaction.VoidOrder(transactionID);

        LogError(ex.ToString());
        Response.Redirect("Checkout", false);
    }

чтобы методы VoidOrder или даже LogError могли бомбить. Прямо сейчас, когда я вызываю VoidOrder, я получаю нулевой ref для transactionID, потому что он вызывает метод BL, и в этом методе BL я повторно выбрасываю, чтобы я мог поймать его на этом более высоком уровне в коде выше. Но если я снова бросаю в ловушку, мне нужно поймать и это.

Ответы [ 5 ]

15 голосов
/ 22 февраля 2010

Вот как мы подходим к проблеме:

Все вызовы с уровня UI / codebehind на другие уровни используют try-catch, где мы всегда ловим пользовательское исключение. Все действия, выполняемые нижележащими слоями, имеют свою собственную функцию try-catch, которая регистрирует, переносит и создает пользовательское исключение. Пользовательский интерфейс может рассчитывать на это и искать обработанные исключения с понятными сообщениями об ошибках.

Codebehind:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    //do something when a button is clicked...
    try
    {
        MyBL.TakeAction()
    }
    catch(MyApplicationCustomException ex)
    {
        //display something to the user, etc.
        ltlErrorPane.Text = ex.Message;

        //or redirect if desired
        if(ex.ErrorType == MyCustomErrorsType.Transactional)
        {
            Response.Redirect("~/Errors/Transaction.aspx");
        }
    }
}

BL:

На бизнес-уровне любые операции, которые могут быть неудачными, используют try-catch, который регистрирует и оборачивает проблему, прежде чем выбросить ее в пользовательский интерфейс.

public class MyBL
{
    public static void TakeAction()
    {
        try
        {
            //do something
        }
        catch(SpecificDotNetException ex)
        {
            //log, wrap and throw
            MyExceptionManagement.LogException(ex)
            throw new MyApplicationCustomException(ex, "Some friendly error message", MyCustomErrorsType.Transactional);
        }
        finally
        {
            //clean up...
        }
    }
}

Обработчик исключений:

Фактический обработчик исключений имеет несколько способов ведения журнала, включая журнал событий, журнал файлов и, наконец, электронную почту, если все остальное не удается. Мы выбираем простой возврат false, если регистратор не может выполнить ни одно из ожидаемых действий. ИМО, это личный выбор, хотя. Мы полагаем, что вероятность сбоя трех методов подряд (ошибка журнала событий, попытка файла журнала, ошибка, попытка электронной почты, ошибка) очень маловероятна. В этом случае мы решили позволить приложению продолжить работу. Другим вариантом будет позволить приложению полностью выйти из строя.

public static class MyExceptionManagement
{
    public static bool LogException(Exception ex)
    {
        try
        {
            //try logging to a log source by priority, 
            //if it fails with all sources, return false as a last resort
            //we choose not to let logging issues interfere with user experience

            //if logging worked
            return true;
        }
        catch(Exception ex)
        {
            //in most cases, using try-catch as a true-false is bad practice
            //but when logging an exception causes an exception itself, we do
            //use this as a well-considered choice.
            return false;
        }
    }
}

Наконец, для обеспечения отказоустойчивости мы реализуем глобальный обработчик событий Application_ErrorGlobal.asax). Это последнее средство для случаев, когда мы не пытались поймать что-либо. Мы обычно регистрируем и перенаправляем на дружественную страницу ошибок. Если вышеуказанная пользовательская обработка ошибок выполнена успешно, очень мало ошибок попадет в глобальный обработчик.

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

5 голосов
/ 22 февраля 2010

Вложенные try/catch блоки неизбежны в приложениях верхнего уровня, которые должны регистрировать, отправлять сообщения или реагировать на исключения другими нетривиальными способами.

Есть способы сократить количество вложенных блоков (например, консолидировать обработку ошибок с помощью обработчика HttpApplication.Error ASP.NET (он же Application_Error)), но вы должны отлавливать любые исключения, созданные вашим кодом обработки, и внедрять план резервного копирования на случай, если ничего не поможет.

1 голос
/ 23 февраля 2010

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

Метод getControl не должен вставлять в него скрипт, ни метод сохранения не должен делать больше, чем сохранение.

Изучите, что именно эти методы должны делать, и на них у вас будет ответ. Это не выглядит так неловко, чтобы обнулить ордер в случае ошибки. Звучит разумно.

1 голос
/ 22 февраля 2010

Еще одним решением вашей проблемы с вложением будет инкапсуляция логики try / catch для внутренних функций (LogError и т. Д.) В этих функциях, вместо того, чтобы вызывать их. Для LogError это имело бы смысл, потому что вы, вероятно, захотите обрабатывать сломанный регистратор ошибок таким же образом, независимо от того, кто пытается регистрировать ошибку.

0 голосов
/ 22 февраля 2010

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

...