예제 #1
0
        private async Task <object> InvokeAsync <TCommand>(TCommand command, Func <TCommand, Task <object> > handler, bool isUpdate) where TCommand : class, IAggregateCommand
        {
            Guard.NotNull(command, nameof(command));

            if (command.ExpectedVersion != EtagVersion.Any && command.ExpectedVersion != Version)
            {
                throw new DomainObjectVersionException(Id.ToString(), GetType(), Version, command.ExpectedVersion);
            }

            if (isUpdate && Version < 0)
            {
                throw new DomainObjectNotFoundException(Id.ToString(), GetType());
            }
            else if (!isUpdate && Version >= 0)
            {
                throw new DomainException("Object has already been created.");
            }

            var previousSnapshot = snapshot;

            try
            {
                var result = await handler(command);

                var events = uncomittedEvents.ToArray();

                if (events.Length > 0)
                {
                    snapshot.Version = NewVersion;

                    await persistence.WriteEventsAsync(events);

                    await persistence.WriteSnapshotAsync(snapshot);
                }

                if (result == null)
                {
                    if (isUpdate)
                    {
                        result = new EntitySavedResult(Version);
                    }
                    else
                    {
                        result = EntityCreatedResult.Create(Id, Version);
                    }
                }

                return(result);
            }
            catch
            {
                snapshot = previousSnapshot;

                throw;
            }
            finally
            {
                ClearUncommittedEvents();
            }
        }
예제 #2
0
        private async Task <T> InvokeSyncedAsync <T>(CommandContext context, Func <T, Task> handler, bool isUpdate) where T : class, IDomainObject
        {
            Guard.NotNull(context, nameof(context));

            var domainCommand  = GetCommand(context);
            var domainObjectId = domainCommand.AggregateId;

            using (await lockPool.LockAsync(Tuple.Create(typeof(T), domainObjectId)))
            {
                var domainObject = await stateFactory.GetSingleAsync <T>(domainObjectId);

                if (domainCommand.ExpectedVersion != EtagVersion.Any && domainCommand.ExpectedVersion != domainObject.Version)
                {
                    throw new DomainObjectVersionException(domainObjectId.ToString(), typeof(T), domainObject.Version, domainCommand.ExpectedVersion);
                }

                await handler(domainObject);

                await domainObject.WriteAsync();

                if (!context.IsCompleted)
                {
                    if (isUpdate)
                    {
                        context.Complete(new EntitySavedResult(domainObject.Version));
                    }
                    else
                    {
                        context.Complete(EntityCreatedResult.Create(domainObjectId, domainObject.Version));
                    }
                }

                return(domainObject);
            }
        }
예제 #3
0
        private async Task <object?> InvokeAsync <TCommand>(TCommand command, Func <TCommand, Task <object?> > handler, Mode mode) where TCommand : class, IAggregateCommand
        {
            Guard.NotNull(command);
            Guard.NotNull(handler);

            if (command.ExpectedVersion > EtagVersion.Any && command.ExpectedVersion != Version)
            {
                throw new DomainObjectVersionException(id.ToString(), GetType(), Version, command.ExpectedVersion);
            }

            if (mode == Mode.Update && Version < 0)
            {
                TryDeactivateOnIdle();

                throw new DomainObjectNotFoundException(id.ToString(), GetType());
            }

            if (mode == Mode.Create && Version >= 0)
            {
                throw new DomainException("Object has already been created.");
            }

            var previousSnapshot = Snapshot;
            var previousVersion  = Version;

            try
            {
                var result = await handler(command);

                var events = uncomittedEvents.ToArray();

                await WriteAsync(events, previousVersion);

                if (result == null)
                {
                    if (mode == Mode.Update || (mode == Mode.Upsert && Version == 0))
                    {
                        result = new EntitySavedResult(Version);
                    }
                    else
                    {
                        result = EntityCreatedResult.Create(id, Version);
                    }
                }

                return(result);
            }
            catch
            {
                RestorePreviousSnapshot(previousSnapshot, previousVersion);

                throw;
            }
            finally
            {
                ClearUncommittedEvents();
            }
        }
예제 #4
0
        private async Task <object?> InvokeAsync <TCommand>(TCommand command, Func <TCommand, Task <object?> > handler, bool isUpdate) where TCommand : class, IAggregateCommand
        {
            Guard.NotNull(command);
            Guard.NotNull(handler);

            if (isUpdate)
            {
                await EnsureLoadedAsync();
            }

            if (command.ExpectedVersion > EtagVersion.Any && command.ExpectedVersion != Version)
            {
                throw new DomainObjectVersionException(id.ToString(), GetType(), Version, command.ExpectedVersion);
            }

            if (isUpdate == true && Version < 0)
            {
                throw new DomainObjectNotFoundException(id.ToString(), GetType());
            }

            var previousSnapshot = Snapshot;
            var previousVersion  = Version;

            try
            {
                var result = await handler(command);

                var events = uncomittedEvents.ToArray();

                await WriteAsync(events, previousVersion);

                if (result == null)
                {
                    if (isUpdate)
                    {
                        result = new EntitySavedResult(Version);
                    }
                    else
                    {
                        result = EntityCreatedResult.Create(id, Version);
                    }
                }

                isLoaded = true;

                return(result);
            }
            catch
            {
                RestorePreviousSnapshot(previousSnapshot, previousVersion);

                throw;
            }
            finally
            {
                ClearUncommittedEvents();
            }
        }
예제 #5
0
        private async Task <object?> InvokeAsync <TCommand>(TCommand command, Func <TCommand, Task <object?> > handler, bool isUpdate) where TCommand : class, IAggregateCommand
        {
            Guard.NotNull(command, nameof(command));
            Guard.NotNull(handler, nameof(handler));

            if (isUpdate)
            {
                await EnsureLoadedAsync();

                if (Version < 0)
                {
                    throw new DomainObjectNotFoundException(uniqueId.ToString());
                }

                if (Version != command.ExpectedVersion && command.ExpectedVersion > EtagVersion.Any)
                {
                    throw new DomainObjectVersionException(uniqueId.ToString(), Version, command.ExpectedVersion);
                }

                if (IsDeleted())
                {
                    throw new DomainException("Object has already been deleted.");
                }

                if (!CanAccept(command))
                {
                    throw new DomainException("Invalid command.");
                }
            }
            else
            {
                command.ExpectedVersion = EtagVersion.Empty;

                if (Version != command.ExpectedVersion)
                {
                    throw new DomainObjectConflictException(uniqueId.ToString());
                }

                if (!CanAcceptCreation(command))
                {
                    throw new DomainException("Invalid command.");
                }
            }

            var previousSnapshot = Snapshot;
            var previousVersion  = Version;

            try
            {
                var result = await handler(command);

                var events = uncomittedEvents.ToArray();

                await WriteAsync(events, previousVersion);

                if (result == null)
                {
                    if (isUpdate)
                    {
                        result = new EntitySavedResult(Version);
                    }
                    else
                    {
                        result = EntityCreatedResult.Create(uniqueId, Version);
                    }
                }

                isLoaded = true;

                return(result);
            }
            catch (InconsistentStateException) when(!isUpdate)
            {
                RestorePreviousSnapshot(previousSnapshot, previousVersion);

                throw new DomainObjectConflictException(uniqueId.ToString());
            }
            catch
            {
                RestorePreviousSnapshot(previousSnapshot, previousVersion);

                throw;
            }
            finally
            {
                ClearUncommittedEvents();
            }
        }