Я пытаюсь использовать 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, я получаю следующую ошибку после транзакцииScope.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, Exception e) в System.Transactions.SinglePhaseEnlistment.InDoubt(исключение e) в System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment) в 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)
Последнее редактирование:
Этот код работает:
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% воспроизводимое.