假设我有一个web/SOAP服务,我如何为Rebus(消息总线)设置和拆除适当的事务上下文?当Rebus调用消息处理程序时,这不是问题,因为Rebus将在调用处理程序之前设置事务上下文-但是相反的情况是,web服务处理程序需要通过Rebus发送/发布消息?
我对如何实现HTTP模块或类似的东西不感兴趣-只有围绕Rebus的基础知识:准备Rebus发送消息需要什么?
web服务代码在与应用程序数据库通信时有自己的事务正在进行。我需要能够设置Rebus时设置数据库事务和提交/回滚Rebus时做相同的数据库。
我在独立命令行程序中也有类似的问题,需要与数据库交互并发送Rebus消息。
Rebus将自动在自己的"环境事务上下文中"登记发送和发布操作,该操作通过静态(*)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(...)
来定制用于获取/设置上下文的访问器,例如:
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模块;)