【问题标题】:Rebus Send in transactionscope在事务范围内 Rebus 发送
【发布时间】:2015-11-26 16:26:59
【问题描述】:

在以前的 (

using (var scope = new TransactionScope())
{
    var ctx = new AmbientTransactionContext();
    sender.Send(recipient.InputQueue, msg, ctx);

    scope.Complete();
}

是否有可能在 Rebus2 中实现相同的行为

【问题讨论】:

    标签: servicebus rebus


    【解决方案1】:

    正如您正确发现的那样,Rebus 版本 >= 0.90.0 不会自动加入环境事务。

    (更新:从 0.99.16 开始,可以拥有所需的行为 - 有关详细信息,请参阅此答案的末尾)

    但这并不意味着 Rebus 不能参与事务 - 它只是使用自己的环境事务机制(不依赖于 System.Transactions,并且将在 Rebus 移植到 .NET 核心时可用)。

    您可以使用 Rebus 的 DefaultTransactionContext 并通过此 AmbientRebusTransactionContext“使其成为环境”:

    /// <summary>
    /// Rebus ambient transaction scope helper
    /// </summary>
    public class AmbientRebusTransactionContext : IDisposable
    {
        readonly DefaultTransactionContext _transactionContext = new DefaultTransactionContext();
    
        public AmbientRebusTransactionContext()
        {
            if (AmbientTransactionContext.Current != null)
            {
                throw new InvalidOperationException("Cannot start a Rebus transaction because one was already active!");
            }
    
            AmbientTransactionContext.Current = _transactionContext;
        }
    
        public Task Complete()
        {
            return _transactionContext.Complete();
        }
    
        public void Dispose()
        {
            AmbientTransactionContext.Current = null;
        }
    }
    

    然后你可以像这样使用它:

    using(var tx = new AmbientRebusTransactionContext())
    {
        await bus.Send(new Message());
    
        await tx.Complete();
    }
    

    或者,如果您在 Web 应用程序中使用它,我建议您将其包装在 OWIN 中间件中,如下所示:

    app.Use(async (context, next) =>
    {
        using (var transactionContext = new AmbientRebusTransactionContext())
        {
            await next();
    
            await transactionContext.Complete();
        }
    });
    

    更新:自 Rebus 0.99.16 以来,已支持以下内容(通过 Rebus.TransactionScope 包):

    using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        scope.EnlistRebus(); //< enlist Rebus in ambient .NET tx
    
        await _bus.SendLocal("hallå i stuen!1");
    
        scope.Complete();
    }
    

    【讨论】:

    • 如果我想加入 Rebus TransactionContext,这种方法是可以的。但是加入 .Net System.Transactions 呢?在我看来,当您在 .net Transactionscope 中执行业务逻辑并希望将 bus.Send 作为此范围的一部分执行时,这种情况很常见
    • 我继续执行您的要求 - 现在您可以在创建事务范围后调用 scope.EnlistRebus(); 以在该范围内加入环境 Rebus 事务 - 请记住 TransactionScopeAsyncFlowOption.Enabled 选项!
    • 在等待您的回复时,我已经实现了自己的包装器,其工作方式与旧式 AmbientTransactionContext : IEnlistmentNotification, ITransactionContext 和新式 AmbientTransactionBridge 一样。但开箱即用的支持是 PERFECT。大概是时候更新github Wiki :)
    猜你喜欢
    • 2018-08-14
    • 1970-01-01
    • 2012-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    相关资源
    最近更新 更多