Контекст теряется при переназначении Transaction.Current в асинхронный / ожидающий код - PullRequest
4 голосов
/ 02 мая 2019

При переназначении Transaction.Current я, похоже, теряю исходное TransactionScopeAsyncFlowOption поведение моего TransactionScope.Код после второго await теряет значение Transaction.Current.

Пример кода (Linqpad):

async Task Main()
{
    Thread.CurrentThread.ManagedThreadId.Dump("before await");
    var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled);
    var transaction = Transaction.Current;

    await Task.Delay(1000).ConfigureAwait(false);

    Thread.CurrentThread.ManagedThreadId.Dump("after first await");
    Transaction.Current = transaction;
    Transaction.Current.Dump(); // not null

    await Task.Delay(1000).ConfigureAwait(false);

    Thread.CurrentThread.ManagedThreadId.Dump("after second await");
    Transaction.Current.Dump(); // is null :/
}

I знаю Я должен использовать using вместо TransactionScope вместо переназначения внешней транзакции, однако по причинам это сделать невозможно.Мне любопытно узнать причину поведения приведенного выше фрагмента и спрашивать, есть ли способы сохранить исходное поведение TransactionScopeAsyncFlowOption.

1 Ответ

1 голос
/ 06 мая 2019

Мне удалось решить проблему, поместив объект Transaction в другой TransactionScope с включенным TransactionScopeAsyncFlowOption:

async Task Main()
{
    var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled);
    var transaction = Transaction.Current;

    await Task.Delay(1000);

    Transaction.Current = transaction;
    Debug.Assert(Transaction.Current != null); // not null

    await Task.Delay(1000);

    Debug.Assert(Transaction.Current == null); // is null :/

    using (var innerScope = new TransactionScope(transaction, TransactionScopeAsyncFlowOption.Enabled))
    {
        // Transaction.Current state is kept across async continuations
        Debug.Assert(Transaction.Current != null); // not null
        await Task.Delay(10);
        Debug.Assert(Transaction.Current != null); // not null
        innerScope.Complete();
    }
}
...