Base solution for your next web application
Open Closed

Manual control of UnitOfWork with NServiceBus #743


User avatar
0
byteplatz created

Hello Halil,

First of all, sorry for the long post, but Im stuck with this.

Im trying to use Abp infrastructure inside a NServiceBus Endpoint and I am having problems with unitofwork.

NServiceBus handle its own transaction and unitofwork when consuming a message and invoking a given handler. (<a class="postlink" href="http://docs.particular.net/nservicebus/pipeline/unit-of-work">http://docs.particular.net/nservicebus/ ... it-of-work</a>)

Inside this handler I am injecting few repositories. Think the Handler as more like a appservice triggered by a message received.

The problem is I cant get control over Abp unitofwork to be able to complete the transaction only after nservicebus has finished working with the message.

The approaches suggested in documentation (<a class="postlink" href="http://aspnetboilerplate.com/Pages/Documents/Unit-Of-Work">http://aspnetboilerplate.com/Pages/Docu ... it-Of-Work</a>) did not work for this specific case.

I really need your help to move forward.

This is the handler code which is instantiated by NServiceBus when a new message is received:

public class CreditGenerationApprovalHandler : IHandleMessages<ApproveCreditGeneration>
    {
        public IBus Bus { get; set; }

        public IRepository<Credit, Guid> CreditRepository { get; set; }

        public void Handle(ApproveCreditGeneration message)
        {
            Credit credit = CreditRepository.Get(message.CreditId.Value);
            credit.Approve();

            Bus.Publish<CreditGenerationApproved>(evt =>
            {
                evt.CreditId = credit.Id;
                evt.CreditValue = credit.Value;
            });
        }
    }

I have integrated the IoC and bootstrapped Abp like this (this is called by NServiceBus upon initialization):

public class AbpBootstrap : INeedInitialization
    {
        public void Customize(BusConfiguration configuration)
        {
            // Initialize Abp infrastructure
            var bootstrapper = new AbpBootstrapper();
            bootstrapper.IocManager.IocContainer.AddFacility<LoggingFacility>(f => f.UseLog4Net().WithConfig(ITSConsts.Log4NetConfigFile));
            bootstrapper.Initialize();
        }
    }

NServiceBus IoC is using Abp Windsor:

// Retrieves current IocContainer from Abp
var container = IocManager.Instance.IocContainer;

// Configure Container into NServiceBus
configuration.UseContainer<WindsorBuilder>(c => c.ExistingContainer(container));

If I don't configure anything, the transaction is aborted at the following method (which is what the documentation states, the method is atomic, it completes the transaction right after its execution):

Credit credit = CreditRepository.Get(message.CreditId.Value);

I cannot work that way because I need to perform other tarnsactional operations like Bus.Publish (MSMQ transactional queue).

If I decorate the Handle method with [UnitOfWork] the handler is not able to call it (can't figure why).

Another approach I have tried is using the IManageUnitsOfWork control for NServiceBus (which I believe I should disable Unitofwork at the handle method) and let NSB control it like :

public class EfUnitOfWorkManager : IManageUnitsOfWork, INeedInitialization
    {
        public ILogger Logger { get; set; }

        public IUnitOfWorkManager UowManager { get; set; }

        private IUnitOfWorkCompleteHandle _unitOfWork;

        public void Customize(BusConfiguration configuration)
        {
            configuration.RegisterComponents(config =>
            {
                config.ConfigureComponent<EfUnitOfWorkManager>(DependencyLifecycle.InstancePerCall);
            });
        }

        public void Begin()
        {
            Logger.Debug("NsbUnitOfWorkManager started.");
            _unitOfWork = UowManager.Begin();
        }

        public void End(Exception ex = null)
        {
            if (ex == null)
            {
                Logger.Debug("NsbUnitOfWorkManager completed.");
                UowManager.Current.SaveChanges();
            }
            else
            {
                Logger.Error("NsbUnitOfWorkManager failed.", ex);
            }
        }
    }

Are there any possibilities to disable the commit trnsaction and let me do it manually like mentioned above at the End method called by NServiceBus ?

Many thanks in advance

Bruno


No answer yet!