/// <summary> /// Discover all command handlers associated with any locatable <see cref="Aggregate"/> type. /// </summary> /// <param name="aggregateStore">The <see cref="Aggregate"/> store.</param> /// <param name="typeLocator">The type locator use to retrieve all known <see cref="Aggregate"/> types.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton command handler dependencies.</param> private static Dictionary<Type, CommandHandler> DiscoverCommandHandlers(IStoreAggregates aggregateStore, ILocateTypes typeLocator, IServiceProvider serviceProvider) { var knownHandleMethods = DiscoverHandleMethods(typeLocator, serviceProvider); var result = new Dictionary<Type, CommandHandler>(); var logMessage = new StringBuilder(); logMessage.AppendLine("Discovered command handlers:"); foreach (var aggregateMapping in knownHandleMethods.OrderBy(kvp => kvp.Key.FullName)) { logMessage.Append(" "); logMessage.Append(aggregateMapping.Key); logMessage.AppendLine(); foreach (var handleMethodMapping in aggregateMapping.Value.OrderBy(kvp => kvp.Key.FullName)) { logMessage.Append(" "); logMessage.Append(handleMethodMapping.Key); logMessage.AppendLine(); if (result.ContainsKey(handleMethodMapping.Key)) throw new MappingException(Exceptions.HandleMethodMustBeAssociatedWithSingleAggregate.FormatWith(aggregateMapping.Key, handleMethodMapping.Key)); result.Add(handleMethodMapping.Key, new CommandHandler(aggregateMapping.Key, handleMethodMapping.Key, aggregateStore, handleMethodMapping.Value)); } } Log.Debug(logMessage.ToString); return result; }
/// <summary> /// Discover all command handlers associated with any locatable <see cref="Aggregate"/> type. /// </summary> /// <param name="aggregateStore">The <see cref="Aggregate"/> store.</param> /// <param name="typeLocator">The type locator use to retrieve all known <see cref="Aggregate"/> types.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton command handler dependencies.</param> private static Dictionary <Type, CommandHandler> DiscoverCommandHandlers(IStoreAggregates aggregateStore, ILocateTypes typeLocator, IServiceProvider serviceProvider) { var knownHandleMethods = DiscoverHandleMethods(typeLocator, serviceProvider); var result = new Dictionary <Type, CommandHandler>(); var logMessage = new StringBuilder(); logMessage.AppendLine("Discovered command handlers:"); foreach (var aggregateMapping in knownHandleMethods.OrderBy(kvp => kvp.Key.FullName)) { logMessage.Append(" "); logMessage.Append(aggregateMapping.Key); logMessage.AppendLine(); foreach (var handleMethodMapping in aggregateMapping.Value.OrderBy(kvp => kvp.Key.FullName)) { logMessage.Append(" "); logMessage.Append(handleMethodMapping.Key); logMessage.AppendLine(); if (result.ContainsKey(handleMethodMapping.Key)) { throw new MappingException(Exceptions.HandleMethodMustBeAssociatedWithSingleAggregate.FormatWith(aggregateMapping.Key, handleMethodMapping.Key)); } result.Add(handleMethodMapping.Key, new CommandHandler(aggregateMapping.Key, handleMethodMapping.Key, aggregateStore, handleMethodMapping.Value)); } } Log.Debug(logMessage.ToString); return(result); }
/// <summary> /// Initializes a new instance of <see cref="CommandHandlerRegistry"/> with the specified <paramref name="typeLocator"/> and <paramref name="serviceProvider"/>. /// </summary> /// <param name="aggregateStore">The <see cref="Aggregate"/> store.</param> /// <param name="typeLocator">The type locator use to retrieve all known <see cref="Aggregate"/> types.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton command handler dependencies.</param> public CommandHandlerRegistry(IStoreAggregates aggregateStore, ILocateTypes typeLocator, IServiceProvider serviceProvider) { Verify.NotNull(typeLocator, nameof(typeLocator)); Verify.NotNull(serviceProvider, nameof(serviceProvider)); knownCommandHandlers = DiscoverCommandHandlers(aggregateStore, typeLocator, serviceProvider); }
/// <summary> /// Initializes a new instance of <see cref="CachedAggregateStore"/> using the specified <paramref name="slidingExpiration"/>. /// </summary> /// <param name="aggregateStore">The underlying <see cref="IStoreAggregates"/> implementation to be decorated.</param> /// <param name="slidingExpiration">The maximum time an <see cref="Aggregate"/> may existing in the cache without being accessed.</param> /// <param name="memoryCache">The underlying cache implementation.</param> internal CachedAggregateStore(IStoreAggregates aggregateStore, TimeSpan slidingExpiration, MemoryCache memoryCache) { Verify.NotNull(memoryCache, nameof(memoryCache)); Verify.NotNull(aggregateStore, nameof(aggregateStore)); Verify.GreaterThanOrEqual(TimeSpan.FromSeconds(1), slidingExpiration, nameof(aggregateStore)); this.memoryCache = memoryCache; this.aggregateStore = aggregateStore; this.slidingExpiration = slidingExpiration; }
/// <summary> /// Initializes a new instance of <see cref="HookableAggregateStore"/> with <paramref name="pipelineHooks"/> safe to enumerate multiple times. /// </summary> /// <param name="aggregateStore">The underlying <see cref="IStoreAggregates"/> implementation to be decorated.</param> /// <param name="pipelineHooks">The set of zero or more <see cref="PipelineHook"/> implementations used to extend <see cref="IStoreAggregates"/> behavior.</param> private HookableAggregateStore(IStoreAggregates aggregateStore, IList <PipelineHook> pipelineHooks) { Verify.NotNull(aggregateStore, nameof(aggregateStore)); this.aggregateStore = aggregateStore; this.preGetHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPreGet).ToArray(); this.postGetHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPostGet).Reverse().ToArray(); this.preSaveHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPreSave).ToArray(); this.postSaveHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPostSave).Reverse().ToArray(); }
/// <summary> /// Initializes a new instance of <see cref="HookableAggregateStore"/> with <paramref name="pipelineHooks"/> safe to enumerate multiple times. /// </summary> /// <param name="aggregateStore">The underlying <see cref="IStoreAggregates"/> implementation to be decorated.</param> /// <param name="pipelineHooks">The set of zero or more <see cref="PipelineHook"/> implementations used to extend <see cref="IStoreAggregates"/> behavior.</param> private HookableAggregateStore(IStoreAggregates aggregateStore, IList<PipelineHook> pipelineHooks) { Verify.NotNull(aggregateStore, nameof(aggregateStore)); this.aggregateStore = aggregateStore; this.preGetHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPreGet).ToArray(); this.postGetHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPostGet).Reverse().ToArray(); this.preSaveHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPreSave).ToArray(); this.postSaveHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPostSave).Reverse().ToArray(); }
/// <summary> /// Initializes a newly created aggregate instance. /// </summary> /// <typeparam name="TAggregate">The type of aggregate to initialize.</typeparam> /// <param name="aggregateStore">The aggregate repository to which the aggregate is to be saved.</param> /// <param name="aggregate">The newly created aggregate.</param> /// <param name="initializer">The aggregate initializer.</param> private static TAggregate Create <TAggregate>(this IStoreAggregates aggregateStore, TAggregate aggregate, Action <TAggregate> initializer) where TAggregate : Aggregate { var context = CommandContext.GetCurrent(); using (var createContext = new CommandContext(aggregate.Id, context.Headers, new CommandEnvelope(aggregate.Id, context.Command))) { initializer.Invoke(aggregate); return((TAggregate)aggregateStore.Save(aggregate, createContext).Aggregate); } }
/// <summary> /// Initializes a new instance of <see cref="CommandHandler"/>. /// </summary> /// <param name="aggregateType">The aggregate type.</param> /// <param name="commandType">The command type.</param> /// <param name="aggregateStore">The aggregate store.</param> /// <param name="executor">The command handler executor.</param> public CommandHandler(Type aggregateType, Type commandType, IStoreAggregates aggregateStore, Action<Aggregate, Command> executor) { Verify.NotNull(executor, nameof(executor)); Verify.NotNull(commandType, nameof(commandType)); Verify.NotNull(aggregateType, nameof(aggregateType)); Verify.NotNull(aggregateStore, nameof(aggregateStore)); Verify.TypeDerivesFrom(typeof(Command), commandType, nameof(commandType)); Verify.TypeDerivesFrom(typeof(Aggregate), aggregateType, nameof(aggregateType)); this.aggregateStore = aggregateStore; this.aggregateType = aggregateType; this.commandType = commandType; this.executor = executor; }
/// <summary> /// Initializes a new instance of <see cref="CommandHandler"/>. /// </summary> /// <param name="aggregateType">The aggregate type.</param> /// <param name="commandType">The command type.</param> /// <param name="aggregateStore">The aggregate store.</param> /// <param name="executor">The command handler executor.</param> public CommandHandler(Type aggregateType, Type commandType, IStoreAggregates aggregateStore, Action <Aggregate, Command> executor) { Verify.NotNull(executor, nameof(executor)); Verify.NotNull(commandType, nameof(commandType)); Verify.NotNull(aggregateType, nameof(aggregateType)); Verify.NotNull(aggregateStore, nameof(aggregateStore)); Verify.TypeDerivesFrom(typeof(Command), commandType, nameof(commandType)); Verify.TypeDerivesFrom(typeof(Aggregate), aggregateType, nameof(aggregateType)); this.aggregateStore = aggregateStore; this.aggregateType = aggregateType; this.commandType = commandType; this.executor = executor; }
/// <summary> /// Gets or creates an aggregate of type <typeparamref name="TAggregate"/> identified by <paramref name="id"/>. /// </summary> /// <typeparam name="TAggregate">The type of aggregate to retrieve or create.</typeparam> /// <param name="aggregateStore">The aggregate store to extend.</param> /// <param name="id">The unique aggregate id.</param> /// <param name="initializer">The aggregate initializer.</param> public static TAggregate GetOrCreate <TAggregate>(this IStoreAggregates aggregateStore, Guid id, Action <TAggregate> initializer) where TAggregate : Aggregate { Verify.NotNull(aggregateStore, nameof(aggregateStore)); Verify.NotNull(initializer, nameof(initializer)); var aggregate = aggregateStore.Get <TAggregate>(id); if (aggregate.Version > 0) { return(aggregate); } return(aggregateStore.Create(aggregate, initializer)); }
/// <summary> /// Creates an aggregate of type <typeparamref name="TAggregate"/> identified by <paramref name="id"/> if does not already exist; otherwise throws an <see cref="InvalidOperationException"/>. /// </summary> /// <typeparam name="TAggregate">The type of aggregate to retrieve.</typeparam> /// <param name="aggregateStore">The aggregate repository from which the aggregate is to be retrieved.</param> /// <param name="id">The unique aggregate id.</param> /// <param name="initializer">The aggregate initializer.</param> public static TAggregate Create <TAggregate>(this IStoreAggregates aggregateStore, Guid id, Action <TAggregate> initializer) where TAggregate : Aggregate { Verify.NotNull(aggregateStore, nameof(aggregateStore)); Verify.NotNull(initializer, nameof(initializer)); var aggregate = aggregateStore.Get <TAggregate>(id); if (aggregate.Version > 0) { throw new InvalidOperationException(Exceptions.AggregateAlreadyExists.FormatWith(typeof(TAggregate), id)); } return(aggregateStore.Create(aggregate, initializer)); }
public CustomerCommandsHandler(IStoreAggregates aggregateEventStore) { _aggregateEventStore = aggregateEventStore; _aggregateEventStore.Publish += OnEventPublished ; }
/// <summary> /// Initializes a new instance of <see cref="CachedAggregateStore"/>. /// </summary> /// <param name="aggregateStore">The underlying <see cref="IStoreAggregates"/> implementation to be decorated.</param> public CachedAggregateStore(IStoreAggregates aggregateStore) : this(aggregateStore, Settings.AggregateStore.CacheSlidingExpiration, new MemoryCache("AggregateCache")) { }
public CustomerCommandsHandler(IStoreAggregates aggregateEventStore) { _aggregateEventStore = aggregateEventStore; _aggregateEventStore.Publish += OnEventPublished; }
/// <summary> /// Initializes a new instance of <see cref="HookableAggregateStore"/>. /// </summary> /// <param name="aggregateStore">The underlying <see cref="IStoreAggregates"/> implementation to be decorated.</param> /// <param name="pipelineHooks">The set of zero or more <see cref="PipelineHook"/> implementations used to extend <see cref="IStoreAggregates"/> behavior.</param> public HookableAggregateStore(IStoreAggregates aggregateStore, IEnumerable<PipelineHook> pipelineHooks) : this(aggregateStore, pipelineHooks.EmptyIfNull().OrderBy(hook => hook.Order).ThenBy(hook => hook.GetType().FullName).ToList()) { }
/// <summary> /// Initializes a new instance of <see cref="HookableAggregateStore"/>. /// </summary> /// <param name="aggregateStore">The underlying <see cref="IStoreAggregates"/> implementation to be decorated.</param> /// <param name="pipelineHooks">The set of zero or more <see cref="PipelineHook"/> implementations used to extend <see cref="IStoreAggregates"/> behavior.</param> public HookableAggregateStore(IStoreAggregates aggregateStore, IEnumerable <PipelineHook> pipelineHooks) : this(aggregateStore, pipelineHooks.EmptyIfNull().OrderBy(hook => hook.Order).ThenBy(hook => hook.GetType().FullName).ToList()) { }