在TransactionScope中发送NServiceBus消息

时间:2012-09-19 12:42:44

标签: asp.net-mvc messaging nservicebus transactionscope

我正在尝试使用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 enlistment)    在System.Transactions.VolatileDemultiplexer.BroadcastInDoubt(VolatileEnlistmentSet& volatiles)    在System.Transactions.TransactionStatePromotedIndoubt.EnterState(InternalTransaction tx)    在System.Transactions.TransactionStatePromotedBase.InDoubtFromEnlistment(InternalTransaction tx)    在System.Transactions.DurableEnlistmentDelegated.InDoubt(InternalEnlistment enlistment,Exception e)    在System.Transactions.SinglePhaseEnlistment.InDoubt(例外e)    在System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment enlistment)    在System.Transactions.TransactionStateDelegatedCommitting.EnterState(InternalTransaction tx)    在System.Transactions.TransactionStateDelegated.BeginCommit(InternalTransaction tx,Boolean asyncCommit,AsyncCallback asyncCallback,Object asyncState)    在System.Transactions.CommittableTransaction.Commit()    在System.Transactions.TransactionScope.InternalDispose()    在System.Transactions.TransactionScope.Dispose()    在HumanResources.Application.Implementations.HolidayService.Book(BookHolidayRequest请求)中的C:\ Users \ paul.davies \ Documents \ GitHub \ EdaCalendarExample \ HumanResources.Application \ Implementations \ HolidayService.cs:第76行    在HumanResources.UI.Controllers.HolidayController.BookUpdate(BookHolidayViewModel viewModel)中的C:\ Users \ paul.davies \ Documents \ GitHub \ EdaCalendarExample \ HumanResources.UI \ Controllers \ HolidayController.cs:第82行    在lambda_method(Closure,ControllerBase,Object [])    在System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase控制器,Object []参数)    在System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext,IDictionary 2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary 2个参数)    在System.Web.Mvc.ControllerActionInvoker。<> c_ DisplayClass15.b _12()    在System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter过滤器,ActionExecutingContext preContext,Func`1 continuation)

最新修改:

此代码有效:

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%可重复的。

2 个答案:

答案 0 :(得分:4)

这可能没有关系,但即使会话刷新模式设置为_session.Flush(),您仍需要在提交TransactionScope之前调用Commit - 这仅适用于NH提供的事务。

答案 1 :(得分:0)

据我所知,当创建一个新的System.Transactions.Transaction时,没有办法得到通知,并且查看NHibernate中的代码它似乎没有任何代码来处理TransactionScope是在创建会话后创建的。

当您创建会话时,它将尝试在当前事务中登记,如果没有,则会话将不会在事务中登记。我怀疑这是导致事务在提交时失败的原因。

我建议在TransactionScope中创建会话 - 同时检查你是否在TransactionScope之前的某个地方调用session.BeginTransaction。