То, когда столько вещей может пойти не так, как надо все, что Вы делаете, попробовать, попробовать, попробовать

Серьезно, как можно обработать все те исключения без схождения с ума? Я прочитал слишком много статей об обработке исключений или что? Я пытался осуществить рефакторинг это пару раз и каждый раз, когда я, кажется, заканчиваю с чем-то еще худшим. Возможно, я должен признать, что исключения действительно происходят и просто любят кодировать просто счастливый путь?;) Так что случилось с этим кодом (помимо факта, что я был достаточно ленив только для броска Exception вместо чего-то более определенного)? И любой ценой, не относитесь ласково ко мне.

public void Export(Database dstDb)
{
    try
    {
        using (DbConnection connection = dstDb.CreateConnection())
        {
            connection.Open();
            DbTransaction transaction = connection.BeginTransaction();
            try
            {
                // Export all data here (insert into dstDb)
                transaction.Commit();
            }
            catch (SqlException sqlex)
            {
                ExceptionHelper.LogException(sqlex);
                try
                {
                    transaction.Rollback();
                }
                catch (Exception rollbackEx)
                {
                    logger.Error("An exception of type " + rollbackEx.GetType() +
                                      " was encountered while attempting to roll back the transaction.");
                }
                throw new Exception("Error exporting message " + Type + " #" + Id + ": [" + sqlex.GetType() + "] " + sqlex.Message, sqlex);
            }
            catch (Exception ex)
            {
                try
                {
                    transaction.Rollback();
                }
                catch (Exception rollbackEx)
                {
                    logger.Error("An exception of type " + rollbackEx.GetType() +
                                      " was encountered while attempting to roll back the transaction.");
                }
                throw new Exception("Error exporting message " + Type + " #" + Id + ": [" + ex.GetType() + "] " + ex.Message, ex);
            }
        }

        try
        {
            Status = MessageStatus.FINISHED;
            srcDb.UpdateDataSet(drHeader.Table.DataSet, HEADERS,
                CreateHeaderInsertCommand(), CreateHeaderUpdateCommand(), null);
        }
        catch (Exception statusEx)
        {
            logger.ErrorException("Failed to change message status to FINISHED: " +
                                    Type + " #" + Id + ": " + statusEx.Message, statusEx);
        }
    }
    catch (Exception importEx)
    {
        try
        {
            Status = MessageStatus.ERROR;
            srcDb.UpdateDataSet(drHeader.Table.DataSet, HEADERS,
                    CreateHeaderInsertCommand(), CreateHeaderUpdateCommand(), null);
        }
        catch (Exception statusEx)
        {
            logger.ErrorException("Failed to change message status to ERROR: " +
                                    Type + " #" + Id + ": " + statusEx.Message, statusEx);
        }
        AddErrorDescription(importEx.Message);
        throw new Exception("Couldn't export message " + Type + " #" + Id + ", exception: " + importEx.Message, importEx);
    }
}

Btw. Так много раз я пытался действительно трудно быть максимально конкретным при формировании вопросов - результатом не были никакие посещения, никакие ответы и никакая идея, как решить проблему. На этот раз я думал обо всех временах, когда чужой вопрос привлек мое внимание, угадайте, что это было правильным поступком :)

Обновление:

Я попытался провести в жизнь некоторые подсказки, и вот то, что я придумал до сих пор. Я решил изменить поведение немного: когда не возможно установить состояние сообщений на ЗАКОНЧЕННЫЙ после успешного экспорта, я считаю это как задание не полностью сделанным, и я откатываю и выдаю исключение. Если Вы, парни все еще имеют в запасе некоторое терпение, сообщенное мне, если это немного лучше. Или бросьте еще некоторую критику в меня. Btw. Спасибо за все ответы я анализирую каждые из них.

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

Я вижу несколько способов извлечь методы здесь, но все они, кажется, смешивают обязанности, которые jgauffin упомянул в его комментарии: руководящее соединение с базой данных, обрабатывая операции базы данных, бизнес-логика (экспортируют данные). Скажите ChangeStatus метод - это немного находится на одном уровне абстракции - Вы изменяете состояние сообщения, и Вы не интересуетесь тем, как эта вещь происходит, как сообщение сохраняется, и т.д. Возможно, я должен использовать шаблон Картопостроителя Данных для дальнейшего разделения обязанностей, но в этом все еще довольно простом сценарии я думал, что мне сойдет с рук Активная Запись. Возможно, целый дизайн является столь замысловатым прямо сейчас, что я не вижу, где сделать сокращения?

public void Export(Database dstDb)
{
    try
    {
        using (DbConnection connection = dstDb.CreateConnection())
        {
            connection.Open();
            using (DbTransaction transaction = connection.BeginTransaction())
            {
                // Export all data here (insert into dstDb)
                ChangeStatus(MessageStatus.FINISHED);
                transaction.Commit();
            }
        }
    }
    catch (Exception exportEx)
    {
        try
        {
            ChangeStatus(MessageStatus.ERROR);
            AddErrorDescription(exportEx.Message);
        }
        catch (Exception statusEx)
        {
            throw new MessageException("Couldn't export message and set its status to ERROR: " +
                    exportExt.Message + "; " + statusEx.Message, Type, Id, statusEx);
        }
        throw new MessageException("Couldn't export message, exception: " + exportEx.Message, Type, Id, exportEx);
    }
}

private void ChangeStatus(MessageStatus status)
{
    try
    {
        Status = status;
        srcDb.UpdateDataSet(drHeader.Table.DataSet, HEADERS,
            CreateHeaderInsertCommand(), CreateHeaderUpdateCommand(), null);
    }
    catch (Exception statusEx)
    {
        throw new MessageException("Failed to change message status to " + status + ":" + statusEx.Message, statusEx);
    }
}

11
задан Community 23 May 2017 в 11:55
поделиться

4 ответа

В дополнение к отличному ответу jgauffin .

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

Правка:

Поскольку повсеместная регистрация исключений имеет как минимум следующие недостатки:

  1. Одно и то же исключение может регистрироваться несколько раз, что приводит к ненужному заполнению журнала. Трудно сказать, сколько ошибок произошло на самом деле.
  2. Если исключение перехватывается и обрабатывается или игнорируется вызывающей стороной, в файле журнала все равно остаются сообщения об ошибках, что, по крайней мере, сбивает с толку.
9
ответ дан 3 December 2019 в 03:34
поделиться
  1. Наборы данных - корень всех зол ;) Попробуйте вместо этого использовать ORM.
  2. Прочитайте о принципе единой ответственности. ваш код делает много разных вещей.
  3. Не ловите исключения только для того, чтобы отбросить их
  4. Используйте оператор using для транзакции и соединения.
  5. Нет необходимости ловить все различные исключения, когда все обработчики исключений делают одно и то же. Детали исключения (тип исключения и свойство Message) предоставят информацию.
14
ответ дан 3 December 2019 в 03:34
поделиться

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

  1. Никогда не генерируйте System.Exception, обычно существует достаточно типов исключений, чтобы удовлетворить ваше требование, если нет, специализируйтесь. См .: http://www.fidelitydesign.net/?p=45
  2. Выбрасывать исключение только в том случае, если сам метод не может делать ничего, кроме генерирования исключения. Если метод может восстанавливать / обрабатывать ожидаемые варианты ввода / поведения, не создавайте исключение. Создание исключений - это ресурсоемкий процесс.
  3. Никогда не ловите исключение только для того, чтобы его повторно выбросить. Поймать и повторно выбросить, если вам нужно выполнить дополнительную работу, например сообщить об исключении или заключить исключение в другое исключение (обычно я делаю это для работы WCF или транзакционной работы).

Это то, что я делаю лично, многие разработчики предпочитают делать это так, как им удобно ....

4
ответ дан 3 December 2019 в 03:34
поделиться

Создайте журнал класс, который обрабатывает откаты для своих собственных сбоев (т. е. пытается SQL, если это не удается, записывает в журнал событий, если это не удается, записывает в локальный файл журнала и т. д.).

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

public void Export(Database dstDb)
{
  try
  {
    using (DbConnection connection = dstDb.CreateConnection())
    {
        connection.Open();
        using (DbTransaction transaction = connection.BeginTransaction())
        {
            // Export all data here (insert into dstDb)
            ChangeStatus(MessageStatus.FINISHED);
            transaction.Commit();
        }
    }
  }
  catch (Exception exportEx)
  {
    LogError(exportEx);// create a log class for cross-cutting concerns 
        ChangeStatus(MessageStatus.ERROR);
        AddErrorDescription(exportEx.Message);

    throw; // throw preserves original call stack for debugging/logging
  }
}

private void ChangeStatus(MessageStatus status)
{
  try
  {
    Status = status;
    srcDb.UpdateDataSet(drHeader.Table.DataSet, HEADERS,
        CreateHeaderInsertCommand(), CreateHeaderUpdateCommand(), null);
  }
  catch (Exception statusEx)
  {
   Log.Error(statusEx);
   throw;
  }
}

Также в любой ситуации, когда вы чувствуете, что необходимы дополнительные блоки try / catch, сделайте их собственным методом, если они слишком уродливые. Мне нравится ответ Стефана Штайнеггера, где вызов верхнего уровня в вашем приложении - лучшее место для перехвата.

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

0
ответ дан 3 December 2019 в 03:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: