How I use domain events with fubuMVC part two

In my previous post I illustrated how I use domain events and enable a pre-commit  and post-commit behaviour on one handler interface.
Here I’m going to illustrate how to plug this into the fubuMVC framework.

In another previous post I showed how an NHibernate simple unit of work can be used in fubuMVC with a dedicated behaviour and now I want to extend that behaviour so that is processes the post-commit actions. Here’s the invoke method of that behaviour:

        public void Invoke()
        {
            _fubuRequest.Set(new Lazy<ISession>(() => _session ?? 
                   (_session = CreateTransactionalSession())));

            try
            {
                InnerBehavior.Invoke();

                if (_session != null)
                    _session.Transaction.Commit();
            }
            catch (Exception)
            {
                if (_session != null)
                    _session.Transaction.Rollback();
                throw;
            }
            finally
            {
                if (_session != null)
                    _session.Dispose();
            }

            ProcessAfterEventConfirmationActions();
        }

This is the existing Invoke code with an extra method added on at the end to process these "after event confirmation" actions. Here's the implementation of that:

        void ProcessAfterEventConfirmationActions()
        {
            var actions = _fubuRequest.Get<List<AfterEventConfirmationAction>>();
            if (actions == null)
                return;

            actions.ForEach(action => action());
        }

Pretty simple stuff - it cycles through the list of after event confirmation actions that it has obtained from the current fubu request. If isolated error handling is required, it should be contained within the action itself.

The next step is to plug this into the domain events processor, but I have a problem. My domain event processor that I showed in my last post is obtained from the static provider delegate:

    public static class DomainEvents
    {
        static Func<IProcessDomainEvents> _domainEventProcessorProvider;

        public static void SetDomainEventProcessorProvider(Func<IProcessDomainEvents> 
                     domainEventProcessorProvider)
        {
            _domainEventProcessorProvider = domainEventProcessorProvider;
        }

        public static void Raise<TEvent>(TEvent domainEvent) where TEvent : IDomainEvent
        {
            var domainEventProcessor = _domainEventProcessorProvider();
            domainEventProcessor.ProcessEvent(domainEvent);
        }
    }

...and this is declared at the bottom of my HttpApplication :

public class Global : HttpApplication
    {
        Container _applicationsContainer;
        IProcessDomainEvents _domainEventsProcessor;

        protected void Application_Start(object sender, EventArgs e)
        {
            FubuApplication
                .For<XercesFubuRegistry>()
                .StructureMap(() =>
                {
                    var container = new Container(new ContainerConfigurer().Configuration);
                    _applicationsContainer = container;
                    return container;
                })
                .Bootstrap(RouteTable.Routes);

            DomainEvents.SetDomainEventProcessorProvider(DomainEventsProcessor);
        }

        private IProcessDomainEvents DomainEventsProcessor()
        {
            return _domainEventsProcessor ??
                    (_domainEventsProcessor = _applicationsContainer.GetInstance<IProcessDomainEvents>());
        }
    }

Because the processor is obtained from the root container, any fubu request it receives will not be the one from the nested container of the current request.
I therefore need to build myself a simple bridge between the two:

    public interface IFubuRequestBridge
    {
        void StoreRequest(IFubuRequest fubuRequest);

        IFubuRequest ObtainRequest();
    }

    public class FubuRequestBridge : IFubuRequestBridge
    {
        public const string FubuRequestKey = "XERCES_FUBUREQUEST";

        public void StoreRequest(IFubuRequest fubuRequest)
        {
            HttpContext.Current.Items[FubuRequestKey] = fubuRequest;
        }

        public IFubuRequest ObtainRequest()
        {
            return HttpContext.Current.Items[FubuRequestKey] as IFubuRequest;
        }
    }

This fubu request bridge can store and provide the current request and simply places it in the current http context.

The storing of the request is performed using a behaviour dedicated to doing only that:

    public class DomainEventsBehaviour : BasicBehavior
    {
        readonly IFubuRequest _fubuRequest;
        readonly IFubuRequestBridge _fubuRequestBridge;

        public DomainEventsBehaviour(IFubuRequest fubuRequest, IFubuRequestBridge fubuRequestBridge) 
                            : base(PartialBehavior.Ignored)
        {
            _fubuRequest = fubuRequest;
            _fubuRequestBridge = fubuRequestBridge;
        }

        protected override DoNext performInvoke()
        {
            _fubuRequestBridge.StoreRequest(_fubuRequest);

            return DoNext.Continue;
        }
    }

Injected with the current fubu request and the bridge, it stores the fuburequest before invoking the next behaviour.
I put this in the fubu registry before the simple unit of work one:

            ApplyConvention<PermanentRedirectionConvention>();
            ApplyConvention<WrapAllConvention<DomainEventsBehaviour>>();
            ApplyConvention<WrapAllConvention<SimpleUnitOfWorkBehaviour>>();
            ApplyConvention<AuthenticationConvention>();

So now I can change my domain event processor to be injected with the bridge – to store the post event confirmation actions it simply retrieves the appropriate fubu request and places them in a list:

    public class DomainEventProcessor : IProcessDomainEvents
    {
        readonly IEnumerable<IHandleDomainEvents> _domainEventHandlers;
        readonly IFubuRequestBridge _fubuRequestBridge;

        public DomainEventProcessor(IEnumerable<IHandleDomainEvents> domainEventHandlers, 
                                               IFubuRequestBridge fubuRequestBridge)
        {
            _domainEventHandlers = domainEventHandlers;
            _fubuRequestBridge = fubuRequestBridge;
        }

        public void ProcessEvent<T>(T domainEvent) where T : IDomainEvent
        {
            _domainEventHandlers.OfType<IHandleDomainEvent<T>>()
                                .ForEach(handler => HandleTheDomainEvent(domainEvent, handler));
        }

        void HandleTheDomainEvent<T>(T domainEvent, IHandleDomainEvent<T> handler) 
                  where T : IDomainEvent
        {
            var afterEventConfirmationAction = handler.Handle(domainEvent);

            var fubuRequest = _fubuRequestBridge.ObtainRequest();

            var currentAfterEventConfirmationActions = 
               fubuRequest.Get<List<AfterEventConfirmationAction>>();
            currentAfterEventConfirmationActions.Add(afterEventConfirmationAction);
        }
    }

And that’s it!
A lot of code in this post, but essentially a working domain events implementation in fubuMVC that does processing within a transaction and post confirmation actions after the committal.



0 comments: