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