易失性IEnlistmentNotification和TransactionScope.AsyncFlowEnabled = true

时间:2014-12-02 07:38:28

标签: c# .net task-parallel-library async-await transactionscope

除了.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<Task> onCommit;

    public SendResourceManager(Func<Task> 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) }));
    }
}

注意:当然这段代码不能编译。它需要我声明commit方法async void。这是令人敬畏的。

所以我的问题是:如何编写一个内部等待异步操作的登记?

1 个答案:

答案 0 :(得分:3)

只要EnlistVolatile不是繁重的CPU占用时间操作,您就可以使用Task.FromResult创建一个基于Task的基于EnlistVolatile的基于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) }));
    }
}

然后在你的方法中使用它:

MessageSender sender = new MessageSender();
await sender.SendAsync(message, options);

可以在你的callstack中等待更高:

{{1}}