Volatile IEnlistmentNotification, TransactionScope.AsyncFlowEnabled = true and complex async / await

This is the next question to the next question:

Volatile IEnlistmentNotification and TransactionScope.AsyncFlowEnabled = true

The approach taken in the question above works as long as you don't have to wait for multiple statements. Let me show you an example:

public class SendResourceManager : IEnlistmentNotification
{
    private readonly Action onCommit;

    public SendResourceManager(Action onCommit)
    {
        this.onCommit = onCommit;
    }

    public void Prepare(PreparingEnlistment preparingEnlistment)
    {
        preparingEnlistment.Prepared();
    }

    public void Commit(Enlistment enlistment)
    {
        Debug.WriteLine("Committing");
        this.onCommit();
        Debug.WriteLine("Committed");
        enlistment.Done();
    }

    public void Rollback(Enlistment enlistment)
    {
        enlistment.Done();
    }

    public void InDoubt(Enlistment enlistment)
    {
        enlistment.Done();
    }
}

public class AsyncTransactionalMessageSender : ISendMessagesAsync
{
    private readonly List<Message> sentMessages = new List<Message>();

    public IReadOnlyCollection<Message> SentMessages
    {
        get { return new ReadOnlyCollection<Message>(this.sentMessages); }
    }

    public async Task SendAsync(Message message)
    {
        if (Transaction.Current != null)
        {
            await Transaction.Current.EnlistVolatileAsync(
                new SendResourceManager(async () => await this.SendInternal(message)), 
                EnlistmentOptions.None);
        }
        else
        {
            await this.SendInternal(message);
        }
    }

    private async Task SendInternal(Message message)
    {
        Debug.WriteLine("Sending");
        await Task.Delay(1000);
        this.sentMessages.Add(message);
        Debug.WriteLine("Sent");
    }
}

    [Test]
    public async Task ScopeRollbackAsync_DoesntSend()
    {
        var sender = new AsyncTransactionalMessageSender();
        using (var tx = new System.Transactions.TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            await sender.SendAsync(new Message("First"));
            await sender.SendAsync(new Message("Second"));
            await sender.SendAsync(new Message("Last"));

            // We do not commit the scope
        }

        sender.SentMessages.Should().BeEmpty();
    }

    [Test]
    public async Task ScopeCompleteAsync_Sends()
    {
        var sender = new AsyncTransactionalMessageSender();
        using (var tx = new System.Transactions.TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            await sender.SendAsync(new Message("First"));
            await sender.SendAsync(new Message("Second"));
            await sender.SendAsync(new Message("Last"));

            tx.Complete();
        }

        sender.SentMessages.Should().HaveCount(3)
            .And.Contain(m => m.Value == "First")
            .And.Contain(m => m.Value == "Second")
            .And.Contain(m => m.Value == "Last");
    }

      

Once you enter Task.Delay as shown in the example above, the generated asynchronous statemachine will never return and will call this.sentMessages.Add(message)

andDebug.WriteLine("Sent")

The problem is that I can now see a way to correctly borrow async code in the assignment notice. Any ideas how to solve this problem?

0
c # async-await transactionscope


source to share


No one has answered this question yet

See similar questions:

3
Volatile IEnlistmentNotification and TransactionScope.AsyncFlowEnabled = true

or similar:

957
How and when to use "async and await"
814
Using async / await with a forEach loop
604
Volatile vs blocking vs blocking
600
How can I run the async Task <T> method synchronously?
268
Waiting for asynchronous operation synchronously and why Wait () will freeze the program here
five
Calling the queue for an asynchronous method
4
Async odbc seems to be synchronous
3
Volatile IEnlistmentNotification and TransactionScope.AsyncFlowEnabled = true
1
Passing selected list item to xaml
1
does the last call in the async call graph really need to be synchronous?



All Articles
Loading...
X
Show
Funny
Dev
Pics