C# Volatile IEnlistmentNotification,TransactionScope.AsyncFlowEnabled=true和复杂异步/等待

C# Volatile IEnlistmentNotification,TransactionScope.AsyncFlowEnabled=true和复杂异步/等待,c#,async-await,transactionscope,C#,Async Await,Transactionscope,这是以下问题的后续问题: 只要你不等待多个陈述,上述问题中接受的方法就有效。让我举一个例子: public class SendResourceManager : IEnlistmentNotification { private readonly Action onCommit; public SendResourceManager(Action onCommit) { this.onCommit = onCommit; } publ

这是以下问题的后续问题:

只要你不等待多个陈述,上述问题中接受的方法就有效。让我举一个例子:

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");
    }
一旦您引入Task.Delay(如上面的示例所示),生成的异步状态机将永远不会返回并调用this.sentMessages.Addmessage和Debug.writelinePresent


问题是我现在看到了在登记通知中正确登记异步代码的方法。您知道如何应对这一挑战吗?

只有在您将调用引入任务时才知道。延迟您正在进行异步调用。在此之前,一切都是同步的。您正在使其异步,但没有任何方法等待其完成。发生了什么事?你期望发生什么事?看看有关的文章,保罗,是的,我知道。这正是我想要实现的用例。在我的例子中,我需要登记到登记中的消息传递基础结构的异步发送调用,如果事务未完成,则不发送消息。因此,任务延迟模拟了实际的异步调用。您没有抓住要点,@DanielMarbach。因为您使用的是异步void,所以无法判断onCommit中的所有代码何时都已执行。所以,当您调用“登记.完成”时,提交代码肯定没有运行。阅读关于async await如何工作的文章。@PauleMorgado是的,我知道。我想确保没有解决办法。因为这样,即使启用了AsyncFlow,TransactionScope也无法与async一起使用。有什么原因不等待async吗?