Серьезно, как можно обработать все те исключения без схождения с ума? Я прочитал слишком много статей об обработке исключений или что? Я пытался осуществить рефакторинг это пару раз и каждый раз, когда я, кажется, заканчиваю с чем-то еще худшим. Возможно, я должен признать, что исключения действительно происходят и просто любят кодировать просто счастливый путь?;) Так что случилось с этим кодом (помимо факта, что я был достаточно ленив только для броска 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);
}
}
В дополнение к отличному ответу jgauffin .
6. не перехватывайте исключения только для того, чтобы их регистрировать. поймать их на самом верхнем уровне и записать туда все исключения.
Правка:
Поскольку повсеместная регистрация исключений имеет как минимум следующие недостатки:
Обработка исключений хорошо обсуждается и реализуется множеством разнообразных способов. Есть несколько правил, которые я стараюсь соблюдать при обработке исключений:
Это то, что я делаю лично, многие разработчики предпочитают делать это так, как им удобно ....
Создайте журнал класс, который обрабатывает откаты для своих собственных сбоев (т. е. пытается 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, сделайте их собственным методом, если они слишком уродливые. Мне нравится ответ Стефана Штайнеггера, где вызов верхнего уровня в вашем приложении - лучшее место для перехвата.
Я полагаю, что отчасти проблема здесь в том, что что-то изменяемое, что заставляет вас пытаться установить статус после сбоя. Если вы можете определить, что ваш объект находится в согласованном состоянии, независимо от того, работает ваша транзакция или нет, вам не нужно беспокоиться об этой части.