TransactionScope допускает частичное обновление даже при ошибках второй службы - PullRequest
0 голосов
/ 26 ноября 2009

У меня был хороший трал через связанные вопросы и найденные предложения, но у меня все еще есть проблема с .NET TransactionScope.

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

Вот метод вызова:

private void TryATransaction()
{
    ServiceReference1.IService1 service = new ServiceReference1.Service1Client();
    ServiceReference2.IService1 service2 = new ServiceReference2.Service1Client();

    using (TransactionScope scope = new TransactionScope())
    {
        service.TestMethod("one");
        service2.UpdateSomethingElse("two");

        scope.Complete();
    }
}

Первый сервис выглядит так (анонимные подключения):

public bool TestMethod(string anything)
{
        using (TransactionScope scope = new TransactionScope())
        {

            // connect to a db
            using (SqlConnection connection = new SqlConnection("Data Source=DATASOURCE;Initial Catalog=DATABASE;Integrated Security=SSPI;Transaction Binding=Explicit Unbind;"))
            {

                connection.Open();
                // save something
                SqlCommand command1 = new SqlCommand("EXECUTE [DATABASE].[dbo].[uspUpdateCustomer] 3, 'test@test.com', 1, null", connection);
                command1.ExecuteNonQuery();
                connection.Close();

            }

            scope.Complete();
        }

    return true;
}

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

1) Если я запускаю это без принудительной ошибки, все поля обновляются нормально.

2) Когда я запускаю это и вырабатываю ошибку во втором сервисе, обновление из первого сервиса фиксируется в базе данных, тогда как второй сервис откатывается (ошибка ПОСЛЕ оператора INSTENETQUERE).

Этот пример кода по существу следует за примерами, найденными здесь: http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

И я добавил Explicit Unbind, что было рекомендовано в других смежных вопросах.

Ваши предложения очень приветствуются - и я рад добавить дополнительную информацию, если она потребуется.

Дополнительная информация

Распределенный идентификатор, кажется, всегда 00000000-0000-0000-0000-000000000000 - я не знаю, является ли это подсказкой.

Вот результат дублирования распределенного идентификатора и локального идентификатора (в указанном порядке)

Текущая транзакция 00000000-0000-0000-0000-000000000000 - f6446876-496d-488c-a21c-1e4c4295d50c: 8

Текущая транзакция 00000000-0000-0000-0000-000000000000 - 7edd5ba3-7f5a-42af-b9ca-37b3862c26a7: 2

Текущая транзакция 00000000-0000-0000-0000-000000000000 - 6fa0e3f7-b655-40ad-8bdd-f0670de79a49: 2

Транзакция запускается с помощью кода за страницей aspx в моем примере приложения.

1 Ответ

1 голос
/ 26 ноября 2009

Редактировать: извините, все было задом наперед.

Скорее всего, проблема связана с использованием транзакций вместе с WCF.

Ознакомьтесь с этой статьей о транзакционных сервисах. В частности, часть о транзакциях в режиме клиент / сервис.

В основном вам нужно:

  • Установите атрибут [TransactionFlow(TransactionFlowOption.Mandatory)] в методах интерфейса OperationContract
  • Установить атрибут [OperationBehavior(TransactionScopeRequired = true)] для их реализации
  • Добавьте TransactionFlowBindingElement к BindingContext вашего сервиса
  • Удалите TransactionScope из реализации вашего сервиса, так как вы используете клиентский TransactionScope.

Каждый метод обслуживания, который успешно завершает свою работу, голосует за успешное выполнение транзакции (при использовании по умолчанию TransactionAutoComplete = true OperationBehavior).

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

...