Exemplo n.º 1
0
        public virtual void LoadAggregateHistory <TAggregateRoot>(TAggregateRoot aggregate, IList <IEvent <TAuthenticationToken> > events = null, bool throwExceptionOnNoEvents = true)
            where TAggregateRoot : IAggregateRoot <TAuthenticationToken>
        {
            IList <IEvent <TAuthenticationToken> > theseEvents = events ?? EventStore.Get <TAggregateRoot>(aggregate.Id).ToList();

            if (!theseEvents.Any())
            {
                if (throwExceptionOnNoEvents)
                {
                    throw new AggregateNotFoundException <TAggregateRoot, TAuthenticationToken>(aggregate.Id);
                }
                return;
            }

            var duplicatedEvents =
                theseEvents.GroupBy(x => x.Version)
                .Select(x => new { Version = x.Key, Total = x.Count() })
                .FirstOrDefault(x => x.Total > 1);

            if (duplicatedEvents != null)
            {
                throw new DuplicateEventException <TAggregateRoot, TAuthenticationToken>(aggregate.Id, duplicatedEvents.Version);
            }

            aggregate.LoadFromHistory(theseEvents);
        }
Exemplo n.º 2
0
        /// <summary>
        /// If <paramref name="events"/> is null, loads the events from <see cref="EventStore"/>, checks for duplicates and then
        /// rehydrates the <paramref name="saga"/> with the events.
        /// </summary>
        /// <typeparam name="TSaga">The <see cref="Type"/> of <see cref="ISaga{TAuthenticationToken}"/>.</typeparam>
        /// <param name="saga">The <typeparamref name="TSaga"/> to rehydrate.</param>
        /// <param name="events">
        /// A collection of <see cref="IEvent{TAuthenticationToken}"/> to replay on the retrieved <see cref="ISaga{TAuthenticationToken}"/>.
        /// If null, the <see cref="IEventStore{TAuthenticationToken}"/> will be used to retrieve a list of <see cref="IEvent{TAuthenticationToken}"/> for you.
        /// </param>
        /// <param name="throwExceptionOnNoEvents">If true will throw an instance of <see cref="SagaNotFoundException{TSaga,TAuthenticationToken}"/> if no aggregate events or provided or found in the <see cref="EventStore"/>.</param>
        public virtual void LoadSagaHistory <TSaga>(TSaga saga, IList <ISagaEvent <TAuthenticationToken> > events = null, bool throwExceptionOnNoEvents = true)
            where TSaga : ISaga <TAuthenticationToken>
        {
            IList <ISagaEvent <TAuthenticationToken> > theseEvents = events ?? EventStore.Get <TSaga>(saga.Id).Cast <ISagaEvent <TAuthenticationToken> >().ToList();

            if (!theseEvents.Any())
            {
                if (throwExceptionOnNoEvents)
                {
                    throw new SagaNotFoundException <TSaga, TAuthenticationToken>(saga.Id);
                }
                return;
            }

            var duplicatedEvents =
                theseEvents.GroupBy(x => x.Version)
                .Select(x => new { Version = x.Key, Total = x.Count() })
                .FirstOrDefault(x => x.Total > 1);

            if (duplicatedEvents != null)
            {
                throw new DuplicateSagaEventException <TSaga, TAuthenticationToken>(saga.Id, duplicatedEvents.Version);
            }

            saga.LoadFromHistory(theseEvents);
        }
Exemplo n.º 3
0
        public async Task Get_WithFromVersionSmallerThanLatestVersion_ReturnsEventsNewerThanFromVersion()
        {
            // arrange
            var aggregateRootId = Guid.NewGuid();

            var events = new IEvent[]
            {
                new ProjectCreated {
                    Id = aggregateRootId, Name = "AnyName", TimeStamp = DateTimeOffset.Now, Version = 1
                },
                new ProjectModified {
                    Id = aggregateRootId, Name = "AnyName", Description = "Any Descrition", TimeStamp = DateTimeOffset.Now, Version = 2
                },
            };

            var serializer = new JsonTextSerializer();
            var publisher  = new Mock <IEventPublisher>();

            var target = new EventStore(this.context.DbContext, serializer, publisher.Object);
            await target.Save(events);

            // act
            IEnumerable <IEvent> actual = await target.Get(aggregateRootId, 1);

            // assert
            Assert.Equal(1, actual.Count());
        }
Exemplo n.º 4
0
        protected virtual TAggregateRoot LoadAggregate <TAggregateRoot>(Guid id, IList <IEvent <TAuthenticationToken> > events = null)
            where TAggregateRoot : IAggregateRoot <TAuthenticationToken>
        {
            var aggregate = AggregateFactory.CreateAggregate <TAggregateRoot>(id);

            IList <IEvent <TAuthenticationToken> > theseEvents = events ?? EventStore.Get <TAggregateRoot>(id).ToList();

            if (!theseEvents.Any())
            {
                throw new AggregateNotFoundException <TAggregateRoot, TAuthenticationToken>(id);
            }

            var duplicatedEvents =
                theseEvents.GroupBy(x => x.Version)
                .Select(x => new { Version = x.Key, Total = x.Count() })
                .FirstOrDefault(x => x.Total > 1);

            if (duplicatedEvents != null)
            {
                throw new DuplicateEventException <TAggregateRoot, TAuthenticationToken>(id, duplicatedEvents.Version);
            }

            aggregate.LoadFromHistory(theseEvents);
            return(aggregate);
        }
Exemplo n.º 5
0
        /// <summary>
        /// If <paramref name="events"/> is null, loads the events from <see cref="IEventStore{TAuthenticationToken}"/>, checks for duplicates and then
        /// rehydrates the <paramref name="aggregate"/> with the events.
        /// </summary>
        /// <typeparam name="TAggregateRoot">The <see cref="Type"/> of <see cref="IAggregateRoot{TAuthenticationToken}"/>.</typeparam>
        /// <param name="aggregate">The <typeparamref name="TAggregateRoot"/> to rehydrate.</param>
        /// <param name="events">
        /// A collection of <see cref="IEvent{TAuthenticationToken}"/> to replay on the retrieved <see cref="IAggregateRoot{TAuthenticationToken}"/>.
        /// If null, the <see cref="IEventStore{TAuthenticationToken}"/> will be used to retrieve a list of <see cref="IEvent{TAuthenticationToken}"/> for you.
        /// </param>
        /// <param name="throwExceptionOnNoEvents">If true will throw an instance of <see cref="AggregateNotFoundException{TAggregateRoot,TAuthenticationToken}"/> if no aggregate events or provided or found in the <see cref="IEventStore{TAuthenticationToken}"/>.</param>
        public void LoadAggregateHistory <TAggregateRoot>(TAggregateRoot aggregate, IList <IEvent <TAuthenticationToken> > events = null, bool throwExceptionOnNoEvents = true)
            where TAggregateRoot : IAggregateRoot <TAuthenticationToken>
        {
            int snapshotVersion = TryRestoreAggregateFromSnapshot(aggregate.Id, aggregate);

            IEnumerable <IEvent <TAuthenticationToken> > theseEvents = events ?? EventStore.Get(aggregate.GetType(), aggregate.Id, false, snapshotVersion).Where(desc => desc.Version > snapshotVersion);

            aggregate.LoadFromHistory(theseEvents);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Save and persist the provided <paramref name="saga"/>, optionally providing the version number the <see cref="ISaga{TAuthenticationToken}"/> is expected to be at.
        /// </summary>
        /// <typeparam name="TSaga">The <see cref="Type"/> of the <see cref="ISaga{TAuthenticationToken}"/>.</typeparam>
        /// <param name="saga">The <see cref="ISaga{TAuthenticationToken}"/> to save and persist.</param>
        /// <param name="expectedVersion">The version number the <see cref="ISaga{TAuthenticationToken}"/> is expected to be at.</param>
        public virtual void Save <TSaga>(TSaga saga, int?expectedVersion = null)
            where TSaga : ISaga <TAuthenticationToken>
        {
            IList <ISagaEvent <TAuthenticationToken> >     uncommittedChanges = saga.GetUncommittedChanges().ToList();
            IEnumerable <ICommand <TAuthenticationToken> > commandsToPublish  = saga.GetUnpublishedCommands();

            if (!uncommittedChanges.Any())
            {
                PublishCommand(commandsToPublish);
                return;
            }

            if (expectedVersion != null)
            {
                IEnumerable <IEvent <TAuthenticationToken> > eventStoreResults = EventStore.Get(saga.GetType(), saga.Id, false, expectedVersion.Value);
                if (eventStoreResults.Any())
                {
                    throw new ConcurrencyException(saga.Id);
                }
            }

            var eventsToPublish = new List <ISagaEvent <TAuthenticationToken> >();

            int i       = 0;
            int version = saga.Version;

            foreach (ISagaEvent <TAuthenticationToken> @event in uncommittedChanges)
            {
                if (@event.Rsn == Guid.Empty)
                {
                    @event.Rsn = saga.Id;
                }
                if (@event.Rsn == Guid.Empty)
                {
                    throw new AggregateOrEventMissingIdException(saga.GetType(), @event.GetType());
                }

                i++;
                version++;

                @event.Version       = version;
                @event.TimeStamp     = DateTimeOffset.UtcNow;
                @event.CorrelationId = CorrelationIdHelper.GetCorrelationId();
                EventStore.Save(saga.GetType(), @event);
                eventsToPublish.Add(@event);
            }

            saga.MarkChangesAsCommitted();
            foreach (ISagaEvent <TAuthenticationToken> @event in eventsToPublish)
            {
                PublishEvent(@event);
            }

            PublishCommand(commandsToPublish);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Save and persist the provided <paramref name="aggregate"/>, optionally providing the version number the <see cref="IAggregateRoot{TAuthenticationToken}"/> is expected to be at.
        /// </summary>
        /// <typeparam name="TAggregateRoot">The <see cref="Type"/> of the <see cref="IAggregateRoot{TAuthenticationToken}"/>.</typeparam>
        /// <param name="aggregate">The <see cref="IAggregateRoot{TAuthenticationToken}"/> to save and persist.</param>
        /// <param name="expectedVersion">The version number the <see cref="IAggregateRoot{TAuthenticationToken}"/> is expected to be at.</param>
        public virtual void Save <TAggregateRoot>(TAggregateRoot aggregate, int?expectedVersion = null)
            where TAggregateRoot : IAggregateRoot <TAuthenticationToken>
        {
            IList <IEvent <TAuthenticationToken> > uncommittedChanges = aggregate.GetUncommittedChanges().ToList();

            if (!uncommittedChanges.Any())
            {
                return;
            }

            if (expectedVersion != null)
            {
                IEnumerable <IEvent <TAuthenticationToken> > eventStoreResults = EventStore.Get(aggregate.GetType(), aggregate.Id, false, expectedVersion.Value);
                if (eventStoreResults.Any())
                {
                    throw new ConcurrencyException(aggregate.Id);
                }
            }

            var eventsToPublish = new List <IEvent <TAuthenticationToken> >();

            int i       = 0;
            int version = aggregate.Version;

            foreach (IEvent <TAuthenticationToken> @event in uncommittedChanges)
            {
                if (@event.Id == Guid.Empty)
                {
                    @event.Id = aggregate.Id;
                }
                if (@event.Id == Guid.Empty)
                {
                    throw new AggregateOrEventMissingIdException(aggregate.GetType(), @event.GetType());
                }

                i++;
                version++;

                @event.Version       = version;
                @event.TimeStamp     = DateTimeOffset.UtcNow;
                @event.CorrelationId = CorrelationIdHelper.GetCorrelationId();
                EventStore.Save(aggregate.GetType(), @event);
                eventsToPublish.Add(@event);
            }

            aggregate.MarkChangesAsCommitted();
            foreach (IEvent <TAuthenticationToken> @event in eventsToPublish)
            {
                PublishEvent(@event);
            }
        }
Exemplo n.º 8
0
        public TAggregateRoot Get <TAggregateRoot>(Guid aggregateId, IList <IEvent <TAuthenticationToken> > events = null)
            where TAggregateRoot : IAggregateRoot <TAuthenticationToken>
        {
            var aggregate       = AggregateFactory.CreateAggregate <TAggregateRoot>();
            int snapshotVersion = TryRestoreAggregateFromSnapshot(aggregateId, aggregate);

            if (snapshotVersion == -1)
            {
                return(Repository.Get <TAggregateRoot>(aggregateId));
            }
            IEnumerable <IEvent <TAuthenticationToken> > theseEvents = events ?? EventStore.Get <TAggregateRoot>(aggregateId, false, snapshotVersion).Where(desc => desc.Version > snapshotVersion);

            aggregate.LoadFromHistory(theseEvents);

            return(aggregate);
        }
Exemplo n.º 9
0
        public virtual IServiceResponseWithResultData <IEnumerable <EventData> > GetEventData(IServiceRequestWithData <TAuthenticationToken, Guid> serviceRequest)
        {
            AuthenticationTokenHelper.SetAuthenticationToken(serviceRequest.AuthenticationToken);
            CorrelationIdHelper.SetCorrelationId(serviceRequest.CorrelationId);

            OnGetEventData(serviceRequest);
            IEnumerable <EventData> results = EventStore.Get(serviceRequest.Data);

            results = OnGotEventData(serviceRequest, results);

            return(new ServiceResponseWithResultData <IEnumerable <EventData> >
            {
                State = ServiceResponseStateType.Succeeded,
                ResultData = results,
                CorrelationId = CorrelationIdHelper.GetCorrelationId()
            });
        }
Exemplo n.º 10
0
        public async Task Get_WithEventsFromOtherAggregateRoot_ReturnsOnlyEventsFromRequestedAggregateRoot()
        {
            // arrange
            var aggregateRoot1Id = Guid.NewGuid();
            var events1          = new IEvent[]
            {
                new ProjectCreated {
                    Id = aggregateRoot1Id, Name = "AnyName", TimeStamp = DateTimeOffset.Now, Version = 1
                },
                new ProjectModified {
                    Id = aggregateRoot1Id, Name = "AnyName", Description = "Any Descrition", TimeStamp = DateTimeOffset.Now, Version = 2
                },
            };

            var aggregateRoot2Id = Guid.NewGuid();
            var events2          = new IEvent[]
            {
                new ProjectCreated {
                    Id = aggregateRoot2Id, Name = "AnyName", TimeStamp = DateTimeOffset.Now, Version = 1
                },
                new ProjectModified {
                    Id = aggregateRoot2Id, Name = "AnyName", Description = "Any Descrition", TimeStamp = DateTimeOffset.Now, Version = 2
                },
            };

            var serializer = new JsonTextSerializer();
            var publisher  = new Mock <IEventPublisher>();

            var target = new EventStore(this.context.DbContext, serializer, publisher.Object);
            await target.Save(events1);

            await target.Save(events2);

            // act
            IEnumerable <IEvent> actual = await target.Get(aggregateRoot1Id, 0);

            // assert
            Assert.Equal(2, actual.Count());
        }
Exemplo n.º 11
0
        public TAggregateRoot Get <TAggregateRoot>(Guid aggregateId, IList <IEvent <TAuthenticationToken> > events = null)
            where TAggregateRoot : IAggregateRoot <TAuthenticationToken>
        {
            string idstring = aggregateId.ToString();

            try
            {
                IList <IEvent <TAuthenticationToken> > theseEvents = null;
                lock (Locks.GetOrAdd(idstring, _ => new object()))
                {
                    TAggregateRoot aggregate;
                    if (IsTracked(aggregateId))
                    {
                        aggregate   = (TAggregateRoot)Cache.Get(idstring);
                        theseEvents = events ?? EventStore.Get <TAggregateRoot>(aggregateId, false, aggregate.Version).ToList();
                        if (theseEvents.Any() && theseEvents.First().Version != aggregate.Version + 1)
                        {
                            Cache.Remove(idstring);
                        }
                        else
                        {
                            aggregate.LoadFromHistory(theseEvents);
                            return(aggregate);
                        }
                    }

                    aggregate = Repository.Get <TAggregateRoot>(aggregateId, theseEvents);
                    Cache.Add(aggregateId.ToString(), aggregate, PolicyFactory.Invoke());
                    return(aggregate);
                }
            }
            catch (Exception)
            {
                Cache.Remove(idstring);
                throw;
            }
        }