【问题标题】:Volatile IEnlistmentNotification and TransactionScope.AsyncFlowEnabled = true不稳定的 IEnlistmentNotification 和 TransactionScope.AsyncFlowEnabled = true
【发布时间】:2015-01-30 09:19:53
【问题描述】:

除了 .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);
    }
}

所以我想要实现的是像这样引入一个 volatile 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) }));
    }
}

注意:当然,这段代码不会编译。它需要我声明提交方法 async void。这太棒了。

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

【问题讨论】:

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


    【解决方案1】:

    只要EnlistVolatile 不是一个耗费大量 CPU 时间的操作,您就可以使用Task.FromResultEnlistVolatile 之上创建一个基于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) }));
        }
    }
    

    可以在你的调用堆栈中等待更高的位置:

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

    【讨论】:

    • 非常感谢!我明天会测试它并标记答案。
    • 这让我可以等待异步发送。但是,例如,如果发送方在内部使用了实际从未等待过的 await Task.Delay(1000) 并且该方法立即返回。有什么想法可以解决这个问题?
    • 我建议发布一个新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 2017-05-11
    • 2018-11-26
    • 2016-10-18
    • 1970-01-01
    相关资源
    最近更新 更多