如何为 Web 服务设置 Rebus 事务上下文

How to set Rebus transaction context for a web service

鉴于我有一个 web/SOAP 服务,我该如何为 Rebus(消息传递总线)设置和拆除适当的事务上下文?当 Rebus 调用消息处理程序时,这不是问题,因为 Rebus 将在调用处理程序之前设置事务上下文 - 但是相反,Web 服务处理程序需要通过 Rebus send/publish 消息吗?

我对如何实现 HTTP 模块或类似模块不感兴趣 - 只有 Rebus 的基础知识:准备 Rebus 发送消息需要什么?

Web 服务代码在与应用程序数据库对话时有自己的事务在进行。我需要能够在设置数据库事务时设置 Rebus,并且在对数据库执行相同操作时 comit/rollback Rebus。

我对需要与数据库交互和发送 Rebus 消息的独立命令行程序有类似的问题。

Rebus 将自动在其自己的 "ambient transaction context" 中获取发送和发布操作,可通过静态 (*) AmbientTransactionContext.Current 属性.

访问

如果您愿意,您可以自己实现 ITransactionContext,但 Rebus 随附了 DefaultTransactionContext

你这样使用它:

using(var context = new DefaultTransactionContext())
{
    AmbientTransactionContext.Current = context;

    // send and publish things in here

    // complete the transaction
    await context.Complete();
}

可以很容易地放置,例如在 OWIN 中间件或类似的东西中。


(*) 属性 是静态的,但底层值绑定到当前执行上下文(通过使用 CallContext.LogicalGet/SetData),这意味着您可以将其视为线程绑定, 很好 属性 它按预期流向延续。

在 Rebus 2.0.2 中,可以通过使用 Action<ITransactionContext>Func<ITransactionContext> 调用 AmbientTransactionContext.SetAccessors(...) 来自定义用于 get/set 上下文的访问器,例如像这样:

AmbientTransactionContext.SetAccessors(
    context => {
        if (HttpContext.Current == null) {
            throw new InvalidOperationException("Can't set the transaction context when there is no HTTP context");
        }
        HttpContext.Current.Items["current-rbs-context"] = context
    },
    () => HttpContext.Current?.Items["current-rbs-context"] as ITransactionContext
);

在这种情况下,即使在使用老式 HTTP 模块时,它也能正常工作;)