Иногда System.ArgumentNullException с использованием TransactionScope и MS DTC

Время от времени я получаю это исключение на нашем рабочем сервере:

System.ArgumentNullException: Value cannot be null.
   at System.Threading.Monitor.Enter(Object obj)
   at System.Data.ProviderBase.DbConnectionPool.TransactedConnectionPool.TransactionEnded(Transaction transaction, DbConnectionInternal transactedObject)
   at System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment enlistment)
   at System.Transactions.TransactionStateDelegatedCommitting.EnterState(InternalTransaction tx)
   at System.Transactions.CommittableTransaction.Commit()
   at System.Transactions.TransactionScope.InternalDispose()
   at System.Transactions.TransactionScope.Dispose()
   //... continues here with references to my DAL code

Какова причина возникновения этого исключения?

Я уже провел некоторое исследование по этому поводу, но пока без особого успеха. Я также читал эти вопросы здесь:

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

Техническая подготовка

  • Это приложение ASP MVC2 и LINQ2SQL на .NET 3.5.
  • У нас есть три виртуальных машины с балансировкой нагрузки по IP-адресу, каждая из которых имеет IIS7.
  • Единый вирутал с SQL server 2008 - он используется веб-серверами

Я должен отметить, что мне не удалось воспроизвести это исключение на моей машине разработки (сервер разработки + SQL Express 2008) и на нашей тестовой машине (виртуальной с одним IIS7 и SQL server 2008 вместе).

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

ОБНОВЛЕНИЕ

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


person mipe34    schedule 12.11.2012    source источник
comment
Мог бы тот, кто проголосовал против, указать, что не так в моем вопросе?   -  person mipe34    schedule 13.02.2013


Ответы (3)


Согласно http://support.microsoft.com/kb/960754, существует проблема с 2.50727.4016 версия System.Data.dll.

Если на вашем сервере есть эта более старая версия, я бы попытался получить обновленную версию от Microsoft.

person Jack Bolding    schedule 21.11.2012
comment
Мы запросили исправление у Microsoft и развернули его на нашем производственном сервере. И теперь кажется, что проблема ушла. Спасибо чувак! - person mipe34; 23.11.2012

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

Если вы посмотрите с помощью отражателя (или любого другого инструмента IL) на внутренний метод TransactedConnectionPool.TransactionEnded, вы увидите, что его реализация изменилась между .NET 3 и .NET 4 ... Полагаю, тогда он не был поточно-ориентированным. Вы можете попробовать сообщить об этом в Microsoft Connect.

person Simon Mourier    schedule 12.11.2012
comment
Спасибо. Я только что разместил это там. Но у них есть только формы для .NET 4.0 и 4.5, поэтому я не думаю, что они возьмутся за такую ​​старую штуку. Мне также пришло в голову, что это может быть ошибка, но мне очень странно, что никто (кроме того, что был в моем обновлении) еще не столкнулся с этой проблемой. - person mipe34; 12.11.2012

Согласно документу MSDN System.Transactions.TransactionScope метод является синхронным и поэтому использует монитор. Документ не говорит, что метод является потокобезопасным, поэтому я думаю, что вы каким-то образом вызываете dispose для одного и того же объекта области транзакции из более чем одного потока. Вы можете использовать статическое свойство объекта transactioncope System.Transactions.Transaction.Current, чтобы узнать, о какой транзакции вы имеете в виду. Возможно, сообщение журнала перед удалением области транзакции может показать, где это происходит ...

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

person Spence    schedule 12.11.2012
comment
Спасибо за ответ. Я не создаю темы самостоятельно. Это довольно простое приложение CRUD, основанное на ASP MVC2. Как может мне помочь информация о транзакции (я вижу, что есть идентификатор распределенной и локальной транзакции, время создания и статус)? Я точно знаю, в какой части моего кода это происходит, но не знаю, в каких условиях. - person mipe34; 12.11.2012
comment
У вас может быть две разные области транзакции, которые используют одну и ту же транзакцию. если обе области попытаются удалить транзакцию, вы столкнетесь с этой ошибкой. Как вы сказали, вы используете ASP.Net, тогда вы, конечно, используете потоки, поскольку каждое отображение страницы потенциально обслуживается в разных потоках. У вас есть статическая или общая библиотека с некоторым состоянием, которое вы используете для кеширования запросов / транзакций sql? - person Spence; 14.11.2012