易失性IEnlistmentNotification和TransactionScope.AsyncFlowEnabled = true
除了.NET 4.5.1之外,TransactionScope上还有一个新选项,可以使用异步流。 这允许编写以下客户端代码
using(var txt = new TransactionScope(..., TransactionScopeAsyncFlowOption.Enabled) { await sender.SendAsync(); }
到现在为止还挺好。 但是当我需要实现一个易变的IEnlistmentNotification时,我正在努力做到这一点。 让我们假设以下场景,假设:我的底层基础架构从下到上完全异步
public class MessageSender : ISendMessages { public async Task SendAsync(TransportMessage message, SendOptions options) { await sender.SendAsync(message); } }
所以我想要实现的是引入像这样的易失性IEnlistmentNotification:
internal class SendResourceManager : IEnlistmentNotification { private readonly Func onCommit; public SendResourceManager(Func onCommit) { this.onCommit = onCommit; } public void Prepare(PreparingEnlistment preparingEnlistment) { preparingEnlistment.Prepared(); } public void Commit(Enlistment enlistment) { await this.onCommit(); enlistment.Done(); } public void Rollback(Enlistment enlistment) { enlistment.Done(); } public void InDoubt(Enlistment enlistment) { enlistment.Done(); } }
和新的发件人
public class MessageSender : ISendMessages { public async Task SendAsync(TransportMessage message, SendOptions options) { // Dirty: Let's assume Transaction.Current is never null Transaction.Current.EnlistVolatile(new SendResourceManager(async () => { await sender.SendAsync(message) })); } }
注意:当然这段代码不能编译。 它需要我声明提交方法async void。 这是令人敬畏的。
所以我的问题是:我如何编写一个可以在内部等待异步操作的登记?
只要EnlistVolatile
不是繁重的CPU绑定耗时操作,您就可以使用Task.FromResult
在EnlistVolatile
创建基于Task
的精简包装器:
public static class TranscationExtensions { public static Task EnlistVolatileAsync(this Transaction transaction, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions) { return Task.FromResult(transaction.EnlistVolatile (enlistmentNotification, enlistmentOptions)); } }
然后在你的方法中使用它:
public class MessageSender : ISendMessages { public Task SendAsync(TransportMessage message, SendOptions options) { return Transaction.Current.EnlistVolatileAsync (new SendResourceManager(async () => { await sender.SendAsync(message) })); } }
在你的callstack中可以等待更高:
MessageSender sender = new MessageSender(); await sender.SendAsync(message, options);