/// <summary>
        ///     Request that a command should be executed.
        /// </summary>
        /// <typeparam name="T">Type of command to execute.</typeparam>
        /// <param name="command">Command to execute</param>
        /// <returns>
        ///     Task which completes once the command has been delivered (and NOT when it has been executed).
        /// </returns>
        /// <exception cref="T:System.ArgumentNullException">command</exception>
        /// <remarks>
        ///     <para>
        ///         The actual execution of an command can be done anywhere at any time. Do not expect the command to be executed
        ///         just because this method returns. That just means
        ///         that the command have been successfully delivered (to a queue or another process etc) for execution.
        ///     </para>
        /// </remarks>
        public async Task ExecuteAsync <T>(T command) where T : Command
        {
            using (var scope = _container.CreateScope())
            {
                if (ScopeCreated != null)
                {
                    var e = new ScopeCreatedEventArgs(scope);
                    ScopeCreated(this, e);
                }


                var handlers = scope.ResolveAll <ICommandHandler <T> >().ToList();
                if (handlers.Count == 0)
                {
                    throw new CqsHandlerMissingException(typeof(T));
                }
                if (handlers.Count > 1)
                {
                    throw new OnlyOneHandlerAllowedException(typeof(T));
                }

                if (GlobalConfiguration.AuthorizationFilter != null)
                {
                    var ctx = new AuthorizationFilterContext(command, handlers);
                    GlobalConfiguration.AuthorizationFilter.Authorize(ctx);
                }

                await handlers[0].ExecuteAsync(command);
                CommandInvoked(this, new CommandInvokedEventArgs(scope, command));
            }
        }
        /// <summary>
        ///     Invoke a query and wait for the result
        /// </summary>
        /// <typeparam name="TResult">Type of result that the query will return</typeparam>
        /// <param name="query">Query to execute.</param>
        /// <returns>
        ///     Task which will complete once we've got the result (or something failed, like a query wait timeout).
        /// </returns>
        /// <exception cref="T:System.ArgumentNullException">query</exception>
        public async Task <TResult> QueryAsync <TResult>(Query <TResult> query)
        {
            var handler = typeof(IQueryHandler <,>).MakeGenericType(query.GetType(), typeof(TResult));

            using (var scope = _container.CreateScope())
            {
                if (ScopeCreated != null)
                {
                    var createdEventArgs = new ScopeCreatedEventArgs(scope);
                    ScopeCreated(this, createdEventArgs);
                }

                var handlerList = scope.ResolveAll(handler);
                var handlers    = handlerList.ToList();

                if (handlers.Count == 0)
                {
                    throw new CqsHandlerMissingException(query.GetType());
                }
                if (handlers.Count != 1)
                {
                    throw new OnlyOneHandlerAllowedException(query.GetType());
                }


                if (GlobalConfiguration.AuthorizationFilter != null)
                {
                    var ctx = new AuthorizationFilterContext(query, handlers);
                    GlobalConfiguration.AuthorizationFilter.Authorize(ctx);
                }

                var method = handler.GetMethod("ExecuteAsync");
                try
                {
                    var   task = (Task)method.Invoke(handlers[0], new object[] { query });
                    await task;
                    var   result1 = ((dynamic)task).Result;
                    if (QueryExecuted != null)
                    {
                        QueryExecuted(this, new QueryExecutedEventArgs(scope, query, handlers[0]));
                    }


                    return(result1);
                }
                catch (TargetInvocationException exception)
                {
                    ExceptionDispatchInfo.Capture(exception.InnerException).Throw();
                    throw new Exception("this will never happen as the line above throws an exception. It's just here to remove a warning");
                }
            }
        }
        /// <summary>
        ///     Invoke a request and wait for the reply
        /// </summary>
        /// <typeparam name="TReply">Type of reply that we should get for the request.</typeparam>
        /// <param name="request">Request that we want a reply for.</param>
        /// <returns>
        ///     Task which will complete once we've got the result (or something failed, like a request wait timeout).
        /// </returns>
        /// <exception cref="T:System.ArgumentNullException">query</exception>
        public async Task <TReply> ExecuteAsync <TReply>(Request <TReply> request)
        {
            var handler = typeof(IRequestHandler <,>).MakeGenericType(request.GetType(), typeof(TReply));

            using (var scope = _container.CreateScope())
            {
                if (ScopeCreated != null)
                {
                    var e = new ScopeCreatedEventArgs(scope);
                    ScopeCreated(this, e);
                }

                var allHandlersAsObjects = scope.ResolveAll(handler);
                var handlers             = allHandlersAsObjects.ToList();

                if (handlers.Count == 0)
                {
                    throw new CqsHandlerMissingException(request.GetType());
                }
                if (handlers.Count != 1)
                {
                    throw new OnlyOneHandlerAllowedException(request.GetType());
                }

                if (GlobalConfiguration.AuthorizationFilter != null)
                {
                    var ctx = new AuthorizationFilterContext(request, handlers);
                    GlobalConfiguration.AuthorizationFilter.Authorize(ctx);
                }


                try
                {
                    var   method = handler.GetMethod("ExecuteAsync");
                    var   task   = (Task)method.Invoke(handlers[0], new object[] { request });
                    await task;
                    var   result = ((dynamic)task).Result;
                    RequestInvoked(this, new RequestInvokedEventArgs(scope, request));
                    return(result);
                }
                catch (TargetInvocationException exception)
                {
                    ExceptionDispatchInfo.Capture(exception.InnerException).Throw();
                    throw new Exception(
                              "this will never happen as the line above throws an exception. It's just here to remove a warning");
                }
            }
        }
        private async Task InvokeHandlerAsync <TEventType>(Type eventHandlerType, TEventType e,
                                                           ICollection <EventHandlerInfo> eventInfo) where TEventType : ApplicationEvent
        {
            using (var scope = _container.CreateScope())
            {
                ScopeCreatedEventArgs createdEventArgs = null;
                if (ScopeCreated != null)
                {
                    createdEventArgs = new ScopeCreatedEventArgs(scope);
                    ScopeCreated(this, createdEventArgs);
                }


                var subscriber = scope.Resolve(eventHandlerType);
                var sw         = new Stopwatch();
                sw.Start();
                try
                {
                    await((IApplicationEventSubscriber <TEventType>)subscriber).HandleAsync(e);
                    eventInfo.Add(new EventHandlerInfo(subscriber.GetType(), sw.ElapsedMilliseconds));
                    if (ScopeClosing != null)
                    {
                        ScopeClosing(this, new ScopeClosingEventArgs(scope)
                        {
                            HandlersWasSuccessful = true
                        });
                    }
                }
                catch (Exception ex)
                {
                    eventInfo.Add(new EventHandlerInfo(subscriber.GetType(), sw.ElapsedMilliseconds)
                    {
                        Failure = new HandlerFailure(subscriber, ex)
                    });
                    if (ScopeClosing != null)
                    {
                        ScopeClosing(this, new ScopeClosingEventArgs(scope)
                        {
                            HandlersWasSuccessful = false
                        });
                    }
                    throw;
                }
            }
        }
Exemple #5
0
        /// <summary>
        ///     Publish a new application event.
        /// </summary>
        /// <typeparam name="TApplicationEvent">Type of event to publish.</typeparam>
        /// <param name="e">Event to publish, must be serializable.</param>
        /// <returns>
        ///     Task triggered once the event has been delivered.
        /// </returns>
        public async Task PublishAsync <TApplicationEvent>(TApplicationEvent e)
            where TApplicationEvent : ApplicationEvent
        {
            using (var scope = _container.CreateScope())
            {
                ScopeCreatedEventArgs createdEventArgs = null;
                if (ScopeCreated != null)
                {
                    createdEventArgs = new ScopeCreatedEventArgs(scope);
                    ScopeCreated(this, createdEventArgs);
                }

                var implementations = scope
                                      .ResolveAll <IApplicationEventSubscriber <TApplicationEvent> >()
                                      .ToList();

                if (GlobalConfiguration.AuthorizationFilter != null)
                {
                    var ctx = new AuthorizationFilterContext(e, implementations);
                    GlobalConfiguration.AuthorizationFilter.Authorize(ctx);
                }

                var  eventInfo = new List <EventHandlerInfo>();
                var  tasks     = implementations.Select(x => PublishEvent(x, e, eventInfo));
                Task task      = null;
                try
                {
                    task = Task.WhenAll(tasks);
                    await task;
                    EventPublished(this, new EventPublishedEventArgs(scope, e, true, eventInfo));
                }
                catch
                {
                    EventPublished(this, new EventPublishedEventArgs(scope, e, false, eventInfo));
                    var failures = eventInfo.Where(x => x.Failure != null).Select(x => x.Failure).ToList();
                    HandlerFailed(this, new EventHandlerFailedEventArgs(e, failures, eventInfo.Count));

                    throw task.Exception;
                }
            }
        }