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; } }
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(); }
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(); }