Вот некоторая предыстория: Периодически наш сайт падает до такой степени, что приходится перезапускать IIS; это почти всегда происходит в течение часа после исправления DLL (мы используем проект веб-сайта, а не проект веб-приложения, поэтому каждая страница ASPX является отдельной библиотекой DLL).
Проведя некоторое исследование, я обнаружил, что наш доморощенный DAL может при отладке привести к тому, что встроенный веб-сервер с Visual Studio фактически перестанет работать и выключится, если обнаружит ошибку SQL в хранимой процедуре (я имею в виду, что это не только генерировать исключение, которое отображается в браузере, на самом деле это говорит о том, что на веб-сервере произошла ошибка и его необходимо закрыть!)
При дальнейшем копании ошибка, похоже, связана с использованием транзакций для всего (включая операторы Select) в DAL. Кажется, происходит следующее:
- Пытается выполнить хранимую процедуру, хранимая процедура завершается сбоем из-за отсутствия/недопустимого столбца или другой ошибки.
- Код приложения ловит ошибку и выдает ее повторно (плохо, да, но я этого не писал).
- Транзакция пытается зафиксироваться, несмотря на исключение, получает
NullReferenceException
в строкеtransaction.Commit()
(кажется, в свойствеConnection
, потому что есть объект транзакции). Кроме того, кажется, что этот NullRef не может быть пойман (я попробовал демонстрацию, которая принудительно завершилась сбоем с недопустимым Sproc, и NullRef так и не был пойман, хотя вывод ошибки дал его тип какSystem.NullReferenceException
) - Транзакция выдает ошибку, которая говорит что-то вроде «Транзакция завершена и больше не может использоваться».
- ??? но веб-сервер VS падает. Отладка этой части, похоже, зависает на указанном выше исключении, никогда не выходя из метода.
Теперь я не знаю, является ли это причиной сбоя IIS, но это кажется довольно подозрительным, и в любом случае это вопиющая ошибка.
Не имея дела с транзакциями раньше и имея о них только общее представление, мой первый вопрос: почему транзакция все еще пытается зафиксироваться после того, как было выдано исключение? Мой второй вопрос заключается в том, как исправить неудачную фиксацию и предположительно бесконечный цикл исключений, пока сервер не умрет. Разве не имеет смысла добавить что-то вроде этого (метод принимает параметр SqlTransaction с именем transaction
):
catch (SqlException se)
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
Устранит ли это небольшое изменение постоянный цикл исключений, который, как мне кажется, приводит к сбою IIS? Сам DAL чрезвычайно хрупок и используется конкретно в сотнях файлов, поэтому я не могу правильно переписать его с нуля.
ИЗМЕНИТЬ Весь блок кода таков (опять же, устаревший код — используется старый помощник блока доступа к данным Microsoft):
public static DataSet ExecuteDatasetStoredProc(SqlConnection conn, String storedProcName, SqlTransaction transaction, params SqlParameter[] storedProcParms)
{
try
{
// Execute the stored proc
if (transaction != null)
{
return SqlHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
else
{
return SqlHelper.ExecuteDataset(conn, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
}
catch (SqlException se)
{
throw new ApplicationException("Error calling " + storedProcName + ". " + se.Message, se);
}
}
Однако, если блок catch выполняется, транзакция все еще пытается зафиксироваться, и это, по-видимому, вызывает зависание.