Example #1
0
        public static async Task <long?> Handle <S, C>(CommandEnvelope <C> commandEnvelope, IAggregate <S> aggregate, IEventStore eventStore, CancellationToken cancel = default) where C : class where S : class
        {
            if (commandEnvelope.AggregateId == null || commandEnvelope.Command == null)
            {
                throw new Exception();
            }

            var streamName = aggregate.GetStreamName(commandEnvelope.AggregateId);

            var(version, state) = await Load(streamName, aggregate, eventStore, cancel);

            var events = aggregate.Handle(state, commandEnvelope.Command)
                         .Select((e, i) => e.CreateEventEnvelope(commandEnvelope.AggregateId, version + i + 1))
                         .ToArray();

            return(await eventStore.Save(streamName, cancel, events));
        }
Example #2
0
        private async Task Save(IAggregate aggregate, string correlationId, string causationId)
        {
            var commitHeaders = new Dictionary <string, object>();

            var metaData = _environment.GetMetaData().MetaData;

            foreach (var item in metaData)
            {
                commitHeaders[item.Key] = item.Value;
            }

            if (!string.IsNullOrEmpty(correlationId))
            {
                commitHeaders[CorrelationIdKey] = correlationId;
            }

            if (!string.IsNullOrEmpty(causationId))
            {
                commitHeaders[CausationIdKey] = causationId;
            }

            commitHeaders[AggregateClrTypeHeader] = aggregate.GetType().AssemblyQualifiedName;
            commitHeaders[AggregateIdHeader]      = aggregate.Id;

            _environment.GetSettings <EventStoreSettings>().ModifyHeaders(commitHeaders);

            var streamName      = aggregate.GetStreamName(_environment);
            var eventStream     = aggregate.GetUncommittedChanges();
            var newEvents       = eventStream.Events.ToList();
            var originalVersion = aggregate.Version - newEvents.Count;

            var versionToExpect = originalVersion == 0 ? ExpectedVersion.Any : originalVersion - 1;

            while (true)
            {
                try
                {
                    await SaveEventsToStream(streamName, versionToExpect, newEvents, commitHeaders).ConfigureAwait(false);

                    break;
                }
                catch (WrongExpectedVersionException ex)
                {
                    _environment.Log(ex, "Events where added to aggregate with id: {0} since last load. Checking for conflicts and trying again...", LogLevel.Warn, aggregate.Id);
                }
                catch (AggregateException ae)
                {
                    if (!(ae.InnerException is WrongExpectedVersionException))
                    {
                        throw;
                    }

                    _environment.Log(ae.InnerException, "Events where added to aggregate with id: {0} since last load. Checking for conflicts and trying again...", LogLevel.Warn, aggregate.Id);
                }

                var storedEvents = (await LoadEventsFromStream(streamName, versionToExpect < 0 ? 0 : versionToExpect, int.MaxValue).ConfigureAwait(false)).ToList();

                var currentVersion = storedEvents.Select(x => x.OriginalEventNumber).OrderByDescending(x => x).FirstOrDefault();

                if (_checkConflicts.HasConflicts(newEvents, storedEvents, _environment))
                {
                    throw new ConflictingEventException(streamName, versionToExpect, currentVersion);
                }

                versionToExpect = currentVersion;
            }

            aggregate.ClearUncommittedChanges();
        }