Подтвердить что ты не робот

Как поддерживать методы async в TransactionScope с Microsoft.Bcl.Async в .NET 4.0?

У меня есть метод, похожий на:

public async Task SaveItemsAsync(IEnumerable<MyItem> items)
{
    using (var ts = new TransactionScope())
    {
        foreach (var item in items)
        {
            await _repository.SaveItemAsync(item);
        }

        await _repository.DoSomethingElse();

        ts.Complete();
    }
}

У этого, конечно, есть проблемы, потому что TransactionScope не играет хорошо с async/await.

Сбой с сообщением:

"TransactionScope должен быть расположен в том же потоке, который был создан."

Я читал о TransactionScopeAsyncFlowOption в этом ответе, который появляется быть тем, что мне нужно.

Однако для этого конкретного проекта у меня есть жесткое требование поддерживать .Net 4.0 и не может обновиться до 4.5 или 4.5.1. Таким образом, поведение async/wait в моем проекте предоставляется пакет Microsoft.Bcl.Async NuGet.

Я не могу найти TransactionScopeAsyncFlowOption в этом или любом другом OOB-пакете. Я просто пропустил его где-то?

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

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

В случае, если это важно, репозиторий использует прямые ADO.Net(SqlConnection, SqlCommand и т.д.) для записи на SQL Server.

UPDATE

Я думал, что у меня есть решение, которое связано с использованием System.Transactions.dll из .Net 4.5.1 и включения его в мой проект. Тем не менее, я обнаружил, что это работало только в моей dev-блоке, потому что у него уже было установлено 4.5.1. Он не работал при развертывании на машине только с .Net 4.0. Он просто дал MissingMethodException. Я ищу решение, которое будет работать с установкой .NET 4.0.

4b9b3361

Ответ 1

Вам необходимо использовать TransactionScopeAsyncFlowOption.Enabled

public static TransactionScope CreateAsyncTransactionScope(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
    {
        var transactionOptions = new TransactionOptions
        {
            IsolationLevel = isolationLevel,
            Timeout = TransactionManager.MaximumTimeout
        };
        return new TransactionScope(TransactionScopeOption.Required, transactionOptions, TransactionScopeAsyncFlowOption.Enabled);
    }

Ответ 2

Не уверен, что это соответствует вашему сценарию, но ConfigureAwait(false) может использоваться в приложении ASP.NET, чтобы убедиться, что ожидаемый вызов функции повторно входит в контекст запроса вызова.

Итак, если этот код работает в приложении ASP.NET, следующий код:

await _repository.SaveItemAsync(item).ConfigureAwait(false);

Обеспечит, чтобы выполнение продолжалось в потоке запроса.