【发布时间】:2012-09-19 12:42:44
【问题描述】:
我正在尝试使用 NHibernate 在与从 MVC 应用程序内部在总线上发送消息相同的事务中保存到数据库:
public void DoSomethingToEntity(Guid id)
{
var session = _sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
using (var transactionScope = new TransactionScope())
{
var myEntity = _session.Get(id);
myEntity.DoSomething();
_session.Save(myEntity);
_bus.Send(myMessage);
transactionScope.Complete();
}
session.Dispose();
}
在配置中,.MsmqTransport() 设置为 .IsTransactional(true)。
如果我在消息处理程序中执行此操作(它被包装在自己的事务中,因此不需要 TransactionScope)那么一切都会按预期工作,如果我包含异常,则两者都会失败。
但是,如果我在 MVC 应用程序中自己的事务中执行此操作,则在离开 using 块时,我会在 transactionScope.Complete() 之后收到以下错误。:
'该操作对于当前的登记状态无效。'
堆栈跟踪:
在 System.Transactions.EnlistmentState.InternalIndoubt(InternalEnlistment 登记)
在 System.Transactions.VolatileDemultiplexer.BroadcastInDoubt(VolatileEnlistmentSet& volatiles)
在 System.Transactions.TransactionStatePromotedIndoubt.EnterState(InternalTransaction tx)
在 System.Transactions.TransactionStatePromotedBase.InDoubtFromEnlistment(InternalTransaction tx)
在 System.Transactions.DurableEnlistmentDelegated.InDoubt(InternalEnlistment 登记,异常 e)
在 System.Transactions.SinglePhaseEnlistment.InDoubt(异常 e)
在 System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment 登记)
在 System.Transactions.TransactionStateDelegatedCommitting.EnterState(InternalTransaction tx)
在 System.Transactions.TransactionStateDelegated.BeginCommit(InternalTransaction tx,布尔 asyncCommit,AsyncCallback asyncCallback,对象 asyncState)
在 System.Transactions.CommittableTransaction.Commit()
在 System.Transactions.TransactionScope.InternalDispose()
在 System.Transactions.TransactionScope.Dispose()
在 C:\Users\paul.davies\Documents\GitHub\EdaCalendarExample\HumanResources.Application\Implementations\HolidayService.cs:line 76 中的 HumanResources.Application.Implementations.HolidayService.Book(BookHolidayRequest 请求)
在 C:\Users\paul.davies\Documents\GitHub\EdaCalendarExample\HumanResources.UI\Controllers\HolidayController.cs:line 82 中的 HumanResources.UI.Controllers.HolidayController.BookUpdate(BookHolidayViewModel viewModel)
在 lambda_method(闭包,ControllerBase,对象 [])
在 System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase 控制器,Object[] 参数)
在 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext 控制器上下文,IDictionary2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 参数)
在 System.Web.Mvc.ControllerActionInvoker.c_DisplayClass15.b_12()
在 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter 过滤器,ActionExecutingContext preContext,Func`1 延续)
最新编辑:
此代码有效:
public void DoSomethingToEntity(Guid id)
{
var session = _sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
using (var transactionScope = new TransactionScope())
{
var myEntity = _session.Get(id);
_bus.Send(myMessage);
transactionScope.Complete();
}
session.Dispose();
}
此代码会产生错误:
public void DoSomethingToEntity(Guid id)
{
var session = _sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
using (var transactionScope = new TransactionScope())
{
var myEntity = _session.Get(id);
myEntity.AnyField = "a new value";
_bus.Send(myMessage);
transactionScope.Complete();
}
session.Dispose();
}
请注意,在这两个示例中我都没有保存实体。不同之处在于第二个示例,我正在修改从 NHibernate 获得的实体。这是 100% 可重现的。
【问题讨论】:
-
是否可以先从 Web 应用程序发送消息,然后让 NSB 进行数据库更新和任何其他后续 Sends()?
-
@AdamFyles 这可能并且会起作用,但会产生性能开销,我确信这是可以避免的。我知道使用 TransactionScope 是可能的,但我无法克服这个错误。
-
致那些投反对票的人:我或其他 Stack Overflow 用户在不解释原因的情况下投反对票对我或其他 Stack Overflow 用户没有帮助。
-
当 sql 驱动程序尝试将 TX 升级为分布式事务时,似乎 EX 发生了(因为 msmq 发送将强制升级)。它在处理程序上运行时起作用的原因是 NSB 已经从 msmq 接收到,因此当 sql 驱动程序登记时,TX 已经是分布式 TX。不知道为什么会发生这种情况
-
这可能不相关,但即使会话刷新模式设置为 Commit,您仍然必须在提交 TransactionScope 之前调用 _session.Flush() - 这仅适用于 NH 提供的事务。
标签: asp.net-mvc messaging nservicebus transactionscope