/// <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; } } }
/// <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; } } }