public void DispatchToView(IViewContext context, DomainEvent domainEvent, TViewInstance view)
        {
            var lastGlobalSequenceNumber = domainEvent.GetGlobalSequenceNumber();

            if (lastGlobalSequenceNumber <= view.LastGlobalSequenceNumber)
            {
                return;
            }

            var domainEventType = domainEvent.GetType();

            var dispatcherMethod = _dispatcherMethods
                                   .GetOrAdd(domainEventType, type => _dispatchToViewGenericMethod.MakeGenericMethod(domainEventType));

            try
            {
                _logger.Debug("Dispatching event {0} to {1} with ID {2}", lastGlobalSequenceNumber, view, view.Id);

                context.CurrentEvent = domainEvent;

                dispatcherMethod.Invoke(this, new object[] { context, domainEvent, view });

                view.LastGlobalSequenceNumber = lastGlobalSequenceNumber;
            }
            catch (Exception exception)
            {
                throw new ApplicationException(string.Format("Could not dispatch {0} to {1}", domainEvent, view), exception);
            }
        }
            public void MaybeApply(DomainEvent domainEvent, RealUnitOfWork realUnitOfWork, long requestedGlobalSequenceNumber)
            {
                // other roots' events are not relevant
                if (domainEvent.GetAggregateRootId() != _aggregateRootInfo.Id)
                {
                    return;
                }

                var globalSequenceNumberFromEvent = domainEvent.GetGlobalSequenceNumber();

                // don't do anything if we are not supposed to go this far
                if (globalSequenceNumberFromEvent > requestedGlobalSequenceNumber)
                {
                    return;
                }

                // don't do anything if the event is in the past
                if (globalSequenceNumberFromEvent <= _globalSequenceNumber)
                {
                    return;
                }

                // if this entry is a future version of the requested version, it's not ok.... sorry!
                if (_globalSequenceNumber > requestedGlobalSequenceNumber)
                {
                    IsOk = false;
                    return;
                }

                try
                {
                    var sequenceNumberFromEvent    = domainEvent.GetSequenceNumber();
                    var expectedNextSequenceNumber = _aggregateRootInfo.SequenceNumber + 1;

                    if (expectedNextSequenceNumber != sequenceNumberFromEvent)
                    {
                        IsOk = false;
                        return;
                    }

                    _aggregateRootInfo.Apply(domainEvent, realUnitOfWork);

                    _globalSequenceNumber = globalSequenceNumberFromEvent;
                }
                catch (Exception exception)
                {
                    _logger.Warn(exception, "Got an error while bringing cache entry for {0} up-to-date to {1}",
                                 _aggregateRootInfo.Id, requestedGlobalSequenceNumber);

                    IsOk = false;
                }
            }
Beispiel #3
0
        internal void ApplyEvent(DomainEvent e, ReplayState replayState)
        {
            // tried caching here with a (aggRootType, eventType) lookup in two levels of concurrent dictionaries.... didn't provide significant perf boost

            var aggregateRootType = GetType();
            var domainEventType   = e.GetType();

            var applyMethod = aggregateRootType.GetMethod("Apply", new[] { domainEventType });

            if (applyMethod == null)
            {
                throw new ApplicationException(
                          string.Format("Could not find appropriate Apply method on {0} - expects a method with a public void Apply({1}) signature",
                                        aggregateRootType, domainEventType.FullName));
            }

            if (CurrentSequenceNumber + 1 != e.GetSequenceNumber())
            {
                throw new ApplicationException(
                          string.Format("Tried to apply event with sequence number {0} to aggregate root of type {1} with ID {2} with current sequence number {3}. Expected an event with sequence number {4}.",
                                        e.GetSequenceNumber(), aggregateRootType, Id, CurrentSequenceNumber, CurrentSequenceNumber + 1));
            }

            var previousReplayState = ReplayState;

            try
            {
                ReplayState = replayState;

                if (ReplayState == ReplayState.ReplayApply)
                {
                    GlobalSequenceNumberCutoff = e.GetGlobalSequenceNumber();
                }

                applyMethod.Invoke(this, new object[] { e });

                GlobalSequenceNumberCutoff = long.MaxValue;
                ReplayState = previousReplayState;
            }
            catch (TargetInvocationException tae)
            {
                throw new ApplicationException(string.Format("Error when applying event {0} to aggregate root with ID {1}", e, Id), tae);
            }

            CurrentSequenceNumber = e.GetSequenceNumber();
        }
Beispiel #4
0
        void Emit <T>(string id, DomainEvent @event)
        {
            @event.Meta[DomainEvent.MetadataKeys.AggregateRootId] = id;

            BeforeEmit(@event);

            TryRegisterId <T>(id);

            Context.Save(typeof(T), @event);

            arrangedEvents.Add(@event.GetGlobalSequenceNumber());

            AfterEmit(@event);

            formatter
            .Block("Given that:")
            .Write(@event, new EventFormatter(formatter))
            .NewLine()
            .NewLine();
        }