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吗?