public void Enrich(Dictionary <string, string> properties, ICommand command, ICommandDispatchContext context)
 {
     if (command is IUserContextCommand userContextCommand)
     {
         properties["UserId"] = userContextCommand.AuthenticatedUserId.ToString();
     }
 }
 public CommandExecutionException(object command, Type handlerType, int handlerExecutionIndex, ICommandDispatchContext commandDispatchContext)
 {
     Command                = command;
     HandlerType            = handlerType;
     HandlerExecutionIndex  = handlerExecutionIndex;
     CommandDispatchContext = commandDispatchContext;
 }
        public async Task AuditPostDispatch(ICommand command, ICommandDispatchContext dispatchContext, long elapsedMilliseconds, CancellationToken cancellationToken)
        {
            if (_registeredPostDispatchAuditors.Count == 0)
            {
                return;
            }

            ICommandAuditSerializer serializer = _auditorSerializerFunc();

            AuditItem auditItem = new AuditItem
            {
                AdditionalProperties = dispatchContext.AdditionalProperties.ToDictionary(x => x.Key, x => x.Value.ToString()),
                CommandId            = null,
                CommandType          = command.GetType().Name,
                CommandTypeFullName  = command.GetType().AssemblyQualifiedName,
                CorrelationId        = dispatchContext.CorrelationId,
                Depth             = dispatchContext.Depth,
                DispatchedUtc     = DateTime.UtcNow,
                SerializedCommand = serializer.Serialize(command),
                Type           = AuditItem.PostDispatchType,
                DispatchTimeMs = elapsedMilliseconds
            };

            // ReSharper disable once SuspiciousTypeConversion.Global - used by consumers of the package
            if (command is IIdentifiableCommand identifiableCommand)
            {
                auditItem.CommandId = identifiableCommand.CommandId;
            }
            _auditItemEnricherPipeline.Enrich(auditItem.AdditionalProperties, command, dispatchContext);
            await AuditPostDispatch(auditItem, cancellationToken);
        }
 public CommandExecutionException(object command, Type handlerType, int handlerExecutionIndex, ICommandDispatchContext commandDispatchContext, string message, Exception innerException) : base(message, innerException)
 {
     Command                = command;
     HandlerType            = handlerType;
     HandlerExecutionIndex  = handlerExecutionIndex;
     CommandDispatchContext = commandDispatchContext;
 }
Example #5
0
 public void Enrich(Dictionary <string, string> properties, ICommand command, ICommandDispatchContext context)
 {
     foreach (Type enricherType in _enrichers)
     {
         IAuditItemEnricher enricher = _enricherCreatorFunc(enricherType);
         enricher.Enrich(properties, command, context);
     }
 }
        public void EnterCreatesInitialContext()
        {
            // Arrange
            Mock <ICommandCorrelationIdProvider>     correlationIdProvider    = new Mock <ICommandCorrelationIdProvider>();
            Mock <ICommandDispatchContextEnrichment> commandContextEnrichment = new Mock <ICommandDispatchContextEnrichment>();

            correlationIdProvider.Setup(x => x.Create()).Returns("someid");
            AsyncLocalCommandScopeManager manager = new AsyncLocalCommandScopeManager(correlationIdProvider.Object, commandContextEnrichment.Object);

            // Act
            ICommandDispatchContext dispatchContext = manager.Enter();

            // Assert
            Assert.Equal("someid", dispatchContext.CorrelationId);
            Assert.Equal(0, dispatchContext.Depth);
        }
        public void EntryAfterFinalExitCreatesNewContext()
        {
            // Arrange
            Mock <ICommandCorrelationIdProvider>     correlationIdProvider    = new Mock <ICommandCorrelationIdProvider>();
            Mock <ICommandDispatchContextEnrichment> commandContextEnrichment = new Mock <ICommandDispatchContextEnrichment>();

            correlationIdProvider.Setup(x => x.Create()).Returns(() => Guid.NewGuid().ToString());
            AsyncLocalCommandScopeManager manager = new AsyncLocalCommandScopeManager(correlationIdProvider.Object, commandContextEnrichment.Object);

            // Act
            ICommandDispatchContext initialDispatchContext = manager.Enter();

            manager.Exit();
            ICommandDispatchContext secondDispatchContext = manager.Enter();

            // Assert
            Assert.NotEqual(initialDispatchContext, secondDispatchContext);
            Assert.NotEqual(initialDispatchContext.CorrelationId, secondDispatchContext.CorrelationId);
        }
        public void RepeatedEntryAndMatchingxitDecrementsToMinusOne()
        {
            // Arrange
            Mock <ICommandCorrelationIdProvider>     correlationIdProvider    = new Mock <ICommandCorrelationIdProvider>();
            Mock <ICommandDispatchContextEnrichment> commandContextEnrichment = new Mock <ICommandDispatchContextEnrichment>();

            correlationIdProvider.Setup(x => x.Create()).Returns("someid");
            AsyncLocalCommandScopeManager manager = new AsyncLocalCommandScopeManager(correlationIdProvider.Object, commandContextEnrichment.Object);

            // Act
            ICommandDispatchContext dispatchContext = manager.Enter();

            manager.Enter();
            manager.Enter();
            manager.Exit();
            manager.Exit();
            manager.Exit();

            // Assert
            Assert.Equal(-1, dispatchContext.Depth);
        }
        public void EnterCreatesInitialContextWithEnrichedProperties()
        {
            // Arrange
            Mock <ICommandCorrelationIdProvider>     correlationIdProvider    = new Mock <ICommandCorrelationIdProvider>();
            Mock <ICommandDispatchContextEnrichment> commandContextEnrichment = new Mock <ICommandDispatchContextEnrichment>();

            commandContextEnrichment.Setup(x => x.GetAdditionalProperties()).Returns(new Dictionary <string, object>
            {
                { "MyProperty", 25 }
            });
            correlationIdProvider.Setup(x => x.Create()).Returns("someid");
            AsyncLocalCommandScopeManager manager = new AsyncLocalCommandScopeManager(correlationIdProvider.Object, commandContextEnrichment.Object);

            // Act
            ICommandDispatchContext dispatchContext = manager.Enter();

            // Assert
            Assert.Equal("someid", dispatchContext.CorrelationId);
            Assert.Equal(25, dispatchContext.AdditionalProperties["MyProperty"]);
            Assert.Equal(0, dispatchContext.Depth);
        }
        public async Task <TResult> ExecuteAsync <TResult>(ICommand <TResult> command, CancellationToken cancellationToken)
        {
            await new SynchronizationContextRemover();

            ICommandDispatchContext dispatchContext = _commandScopeManager.GetCurrent();
            Stopwatch stopwatch = _collectMetrics ? Stopwatch.StartNew() : null;

            try
            {
                TResult result = await ExecuteCommandWithHandlers(command, dispatchContext, cancellationToken);

                await _commandAuditPipeline.AuditExecution(command, dispatchContext, stopwatch?.ElapsedMilliseconds ?? 0, true, cancellationToken);

                return(result);
            }
            catch (Exception)
            {
                await _commandAuditPipeline.AuditExecution(command, dispatchContext, stopwatch?.ElapsedMilliseconds ?? 0, false, cancellationToken);

                throw;
            }
        }
        private async Task <TResult> ExecuteCommandWithHandlers <TResult>(ICommand <TResult> command, ICommandDispatchContext dispatchContext, CancellationToken cancellationToken)
        {
            IReadOnlyCollection <IPrioritisedCommandHandler> handlers = _commandRegistry.GetPrioritisedCommandHandlers(command);

            if (handlers == null || handlers.Count == 0)
            {
                throw new MissingCommandHandlerRegistrationException(command.GetType(),
                                                                     "No command actors registered for execution of command");
            }
            TResult result = default(TResult);

            int handlerIndex = 0;

            foreach (IPrioritisedCommandHandler handlerTemplate in handlers)
            {
                object baseHandler = null;
                try
                {
                    baseHandler = _commandHandlerFactory.Create(handlerTemplate.CommandHandlerType);

                    if (baseHandler is ICommandHandler handler)
                    {
                        result = await _commandHandlerExecuter.ExecuteAsync(handler, command, result, cancellationToken);
                    }
                    else
                    {
                        if (baseHandler is IPipelineAwareCommandHandler chainHandler)
                        {
                            PipelineAwareCommandHandlerResult <TResult> chainResult =
                                await _pipelineAwareCommandHandlerExecuter.ExecuteAsync(chainHandler, command, result, cancellationToken);

                            result = chainResult.Result;
                            if (chainResult.ShouldStop)
                            {
                                break;
                            }
                        }
                        else
                        {
                            throw new UnableToExecuteHandlerException("Unexpected result type");
                        }
                    }
                }
                catch (Exception ex)
                {
                    bool shouldContinue =
                        await _commandExecutionExceptionHandler.HandleException(ex, baseHandler, handlerIndex, command,
                                                                                dispatchContext);

                    if (!shouldContinue)
                    {
                        break;
                    }
                }
                handlerIndex++;
            }

            return(result);
        }
Example #12
0
 public Task AuditWithNoPayload(Guid commandId, string commandType, ICommandDispatchContext dispatchContext)
 {
     throw new NotImplementedException();
 }
 public CommandDispatchException(TCommand command, ICommandDispatchContext commandDispatchContext, Type dispatcherType)
 {
     Command = command;
     CommandDispatchContext = commandDispatchContext;
     DispatcherType         = dispatcherType;
 }
 public CommandDispatchException(TCommand command, ICommandDispatchContext commandDispatchContext, Type dispatcherType, string message, Exception innerException) : base(message, innerException)
 {
     Command = command;
     CommandDispatchContext = commandDispatchContext;
     DispatcherType         = dispatcherType;
 }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="command">The command being dispatched</param>
 /// <param name="commandDispatchContext">The dispatch context</param>
 /// <param name="dispatcherType">The type of dispatcher in use</param>
 /// <param name="message">Error message</param>
 public CommandDispatchException(object command, ICommandDispatchContext commandDispatchContext, Type dispatcherType, string message) : base(message)
 {
     Command = command;
     CommandDispatchContext = commandDispatchContext;
     DispatcherType         = dispatcherType;
 }
 public Task <bool> HandleException <TResult>(Exception ex, object handler, int handlerExecutionIndex, ICommand <TResult> command,
                                              ICommandDispatchContext dispatchContext)
 {
     throw new DispatcherException($"Error occurred performing operation {command.GetType().Name}", ex);
 }
        public async Task <CommandResult <TResult> > DispatchAsync <TResult>(ICommand <TResult> command, CancellationToken cancellationToken)
        {
            await new SynchronizationContextRemover();

            ICommandDispatchContext dispatchContext = _commandScopeManager.Enter();

            try
            {
                CommandResult <TResult> dispatchResult        = null;
                CommandResult           wrappedDispatchResult = null;
                ICommandExecuter        executer   = null;
                ICommandDispatcher      dispatcher = null;
                ICommand unwrappedCommand          = command;
                if (command is NoResultCommandWrapper wrappedCommand)
                {
                    unwrappedCommand = wrappedCommand.Command;
                }

                // we specifically audit BEFORE dispatch as this allows us to capture intent and a replay to
                // occur even if dispatch fails
                // (there is also an audit opportunity after execution completes and I'm considering putting one in
                // on dispatch success)
                await _auditor.AuditPreDispatch(unwrappedCommand, dispatchContext, cancellationToken);

                try
                {
                    Stopwatch stopwatch = _collectMetrics ? Stopwatch.StartNew() : null;
                    Func <ICommandDispatcher> dispatcherFunc = _commandRegistry.GetCommandDispatcherFactory(command);
                    if (dispatcherFunc != null)
                    {
                        dispatcher = dispatcherFunc();
                        if (command != unwrappedCommand)
                        {
                            wrappedDispatchResult = await dispatcher.DispatchAsync(unwrappedCommand, cancellationToken);
                        }
                        else
                        {
                            dispatchResult = await dispatcher.DispatchAsync(command, cancellationToken);
                        }
                        executer = dispatcher.AssociatedExecuter;
                    }
                    await _auditor.AuditPostDispatch(unwrappedCommand, dispatchContext, stopwatch?.ElapsedMilliseconds ?? -1, cancellationToken);

                    if ((dispatchResult != null && dispatchResult.DeferExecution) || (wrappedDispatchResult != null && wrappedDispatchResult.DeferExecution))
                    {
                        return(new CommandResult <TResult>(default(TResult), true));
                    }
                }
                catch (Exception ex)
                {
                    throw new CommandDispatchException(unwrappedCommand, dispatchContext.Copy(), dispatcher?.GetType() ?? GetType(), "Error occurred during command dispatch", ex);
                }

                if (executer == null)
                {
                    executer = AssociatedExecuter;
                }
                return(new CommandResult <TResult>(await executer.ExecuteAsync(command, cancellationToken), false));
            }
            finally
            {
                _commandScopeManager.Exit();
            }
        }
 public Task <bool> HandleException <TResult>(Exception ex, object handler, int handlerExecutionIndex, ICommand <TResult> command, ICommandDispatchContext dispatchContext)
 {
     throw new CommandExecutionException(command, handler?.GetType(), handlerExecutionIndex, dispatchContext?.Copy(), "Error occurred during command execution", ex);
 }