/// <summary> /// Discover all event handlers associated with any locatable class marked with <see cref="EventHandlerAttribute"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator use to retrieve all known classes marked with <see cref="EventHandlerAttribute"/>.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> private static Dictionary <Type, EventHandler[]> DiscoverEventHandlers(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy <IPublishCommands> commandPublisher) { var knownEvents = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.DerivesFrom(typeof(Event))); var knownHandlers = DiscoverHandleMethods(typeLocator, serviceProvider, sagaStore, commandPublisher); var result = new Dictionary <Type, EventHandler[]>(); var logMessage = new StringBuilder(); logMessage.AppendLine("Discovered event handlers:"); foreach (var eventType in knownEvents.OrderBy(type => type.FullName)) { var eventHandlers = eventType.GetTypeHierarchy().Reverse() .Where(knownHandlers.ContainsKey) .SelectMany(type => knownHandlers[type]) .OrderBy(handler => handler is SagaEventHandler) .ThenBy(handler => handler.HandlerType.AssemblyQualifiedName) .ToArray(); logMessage.Append(" "); logMessage.Append(eventType); logMessage.AppendLine(); foreach (var eventHandler in eventHandlers) { logMessage.Append(" "); logMessage.Append(eventHandler.HandlerType); logMessage.AppendLine(); } result.Add(eventType, eventHandlers); } 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> /// 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 event handlers methods associated with any locatable class marked with with <see cref="EventHandlerAttribute"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator use to retrieve all known classes marked with <see cref="EventHandlerAttribute"/>.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> private static Dictionary <Type, List <EventHandler> > DiscoverHandleMethods(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy <IPublishCommands> commandPublisher) { var handlerTypes = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.GetCustomAttribute <EventHandlerAttribute>() != null); var knownEventHandlers = new Dictionary <Type, List <EventHandler> >(); foreach (var handlerType in handlerTypes) { var handleMethods = GetHandleMethods(handlerType, serviceProvider); var sagaMetadata = typeof(Saga).IsAssignableFrom(handlerType) ? GetSagaMetadata(handlerType, handleMethods) : null; foreach (var handleMethod in handleMethods) { List <EventHandler> eventHandlers; Type eventType = handleMethod.Key; if (!knownEventHandlers.TryGetValue(eventType, out eventHandlers)) { knownEventHandlers.Add(eventType, eventHandlers = new List <EventHandler>()); } var eventHandler = new EventHandler(handlerType, eventType, handleMethod.Value, GetHandlerFactory(handlerType, serviceProvider)); if (sagaMetadata != null) { eventHandler = eventType == typeof(Timeout) ? new SagaTimeoutHandler(eventHandler, sagaMetadata, sagaStore, commandPublisher) : new SagaEventHandler(eventHandler, sagaMetadata, sagaStore, commandPublisher); } eventHandlers.Add(eventHandler); } } return(knownEventHandlers); }
public IStream CatchUp(string streamName, ILocateTypes typeLocator) { return new CatchUpStream( _logger, _eventStore, typeLocator, streamName ); }
/// <summary> /// Discover all known <see cref="Aggregate"/> implementations known to the specified <paramref name="typeLocator"/>. /// </summary> /// <param name="typeLocator">The type locator used to retrieve all <see cref="Aggregate"/> type information.</param> private static IDictionary<Type, ApplyMethodCollection> DiscoverAggregates(ILocateTypes typeLocator) { var aggregateTypes = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.DerivesFrom(typeof(Aggregate))); var result = new Dictionary<Type, ApplyMethodCollection>(); foreach (var aggregateType in aggregateTypes) result.Add(aggregateType, DiscoverApplyMethods(aggregateType)); return result; }
public IStream Persistent(string streamName, string groupName, ILocateTypes typeLocator) { return new PersistentStream( _logger, _eventStore, _credentials, typeLocator, streamName, groupName ); }
public CatchUpStream( ILogger<IEventStore> logger, IEventStoreConnection eventStore, ILocateTypes typeLocator, string streamName) { _logger = logger; _eventStore = eventStore; _typeLocator = typeLocator; _streamName = streamName; }
/// <summary> /// Discover all known <see cref="Aggregate"/> implementations known to the specified <paramref name="typeLocator"/>. /// </summary> /// <param name="typeLocator">The type locator used to retrieve all <see cref="Aggregate"/> type information.</param> private static IDictionary <Type, ApplyMethodCollection> DiscoverAggregates(ILocateTypes typeLocator) { var aggregateTypes = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.DerivesFrom(typeof(Aggregate))); var result = new Dictionary <Type, ApplyMethodCollection>(); foreach (var aggregateType in aggregateTypes) { result.Add(aggregateType, DiscoverApplyMethods(aggregateType)); } return(result); }
/// <summary> /// Initializes a new instance of <see cref="SqlSagaStore"/>. /// </summary> /// <param name="dialect">The database dialect associated with this <see cref="SqlSagaStore"/>.</param> /// <param name="serializer">The <see cref="ISerializeObjects"/> used to store binary data.</param> /// <param name="typeLocator">The type locator use to retrieve all known <see cref="Saga"/> types.</param> public SqlSagaStore(ISagaStoreDialect dialect, ISerializeObjects serializer, ILocateTypes typeLocator) { Verify.NotNull(typeLocator, nameof(typeLocator)); Verify.NotNull(serializer, nameof(serializer)); Verify.NotNull(dialect, nameof(dialect)); this.dialect = dialect; this.serializer = serializer; this.typeToGuidMap = GetKnownSagas(typeLocator); this.guidToTypeMap = typeToGuidMap.ToDictionary(item => item.Value, item => item.Key); Initialize(); }
/// <summary> /// Initializes a new instance of <see cref="EventHandlerRegistry"/> with the specified <paramref name="typeLocator"/> and <paramref name="serviceProvider"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator used to retrieve all known <see cref="Event"/> types.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> public EventHandlerRegistry(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy<IPublishCommands> commandPublisher) { Verify.NotNull(sagaStore, nameof(sagaStore)); Verify.NotNull(typeLocator, nameof(typeLocator)); Verify.NotNull(serviceProvider, nameof(serviceProvider)); Verify.NotNull(commandPublisher, nameof(commandPublisher)); knownEventHandlers = DiscoverEventHandlers(typeLocator, serviceProvider, sagaStore, commandPublisher); knownSagaTimeoutHandlers = knownEventHandlers.Where(item => typeof(Timeout).IsAssignableFrom(item.Key)) .SelectMany(item => item.Value) .OfType<SagaEventHandler>() .Distinct(item => item.HandlerType) .ToDictionary(item => item.HandlerType, item => new EventHandler[] { item }); }
/// <summary> /// Initializes a new instance of <see cref="EventHandlerRegistry"/> with the specified <paramref name="typeLocator"/> and <paramref name="serviceProvider"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator used to retrieve all known <see cref="Event"/> types.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> public EventHandlerRegistry(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy <IPublishCommands> commandPublisher) { Verify.NotNull(sagaStore, nameof(sagaStore)); Verify.NotNull(typeLocator, nameof(typeLocator)); Verify.NotNull(serviceProvider, nameof(serviceProvider)); Verify.NotNull(commandPublisher, nameof(commandPublisher)); knownEventHandlers = DiscoverEventHandlers(typeLocator, serviceProvider, sagaStore, commandPublisher); knownSagaTimeoutHandlers = knownEventHandlers.Where(item => typeof(Timeout).IsAssignableFrom(item.Key)) .SelectMany(item => item.Value) .OfType <SagaEventHandler>() .Distinct(item => item.HandlerType) .ToDictionary(item => item.HandlerType, item => new EventHandler[] { item }); }
public PersistentStream( ILogger<IEventStore> logger, IEventStoreConnection eventStore, UserCredentials credentials, ILocateTypes typeLocator, string streamName, string groupName) { _logger = logger; _eventStore = eventStore; _credentials = credentials; _typeLocator = typeLocator; _streamName = streamName; _groupName = groupName; }
/// <summary> /// Generate unique saga type identifiers for all locatable <see cref="Saga"/> types. /// </summary> /// <param name="typeLocator">The type locator use to retrieve all known <see cref="Saga"/> types.</param> private static Dictionary <Type, Guid> GetKnownSagas(ILocateTypes typeLocator) { var knownSagas = typeLocator.GetTypes(type => type.IsClass && !type.IsAbstract && type.DerivesFrom(typeof(Saga))).ToDictionary(type => type, HashType); var logMessage = new StringBuilder(); logMessage.AppendLine("Discovered sagas:"); foreach (var saga in knownSagas) { logMessage.Append(" "); logMessage.AppendFormat("{0} - {1}", saga.Key, saga.Value); logMessage.AppendLine(); } Log.Debug(logMessage.ToString); return(knownSagas); }
/// <summary> /// Discover all command handlers methods associated with any locatable <see cref="Aggregate"/> type. /// </summary> /// <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, HandleMethodCollection> DiscoverHandleMethods(ILocateTypes typeLocator, IServiceProvider serviceProvider) { var aggregateTypes = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.DerivesFrom(typeof(Aggregate))); var knownCommandHandlers = new Dictionary <Type, HandleMethodCollection>(); foreach (var aggregateType in aggregateTypes) { var handleMethods = GetHandleMethods(aggregateType, serviceProvider); knownCommandHandlers.Add(aggregateType, handleMethods); } return(knownCommandHandlers); }
/// <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 event handlers associated with any locatable class marked with <see cref="EventHandlerAttribute"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator use to retrieve all known classes marked with <see cref="EventHandlerAttribute"/>.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> private static Dictionary<Type, EventHandler[]> DiscoverEventHandlers(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy<IPublishCommands> commandPublisher) { var knownEvents = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.DerivesFrom(typeof(Event))); var knownHandlers = DiscoverHandleMethods(typeLocator, serviceProvider, sagaStore, commandPublisher); var result = new Dictionary<Type, EventHandler[]>(); var logMessage = new StringBuilder(); logMessage.AppendLine("Discovered event handlers:"); foreach (var eventType in knownEvents.OrderBy(type => type.FullName)) { var eventHandlers = eventType.GetTypeHierarchy().Reverse() .Where(knownHandlers.ContainsKey) .SelectMany(type => knownHandlers[type]) .OrderBy(handler => handler is SagaEventHandler) .ThenBy(handler => handler.HandlerType.AssemblyQualifiedName) .ToArray(); logMessage.Append(" "); logMessage.Append(eventType); logMessage.AppendLine(); foreach (var eventHandler in eventHandlers) { logMessage.Append(" "); logMessage.Append(eventHandler.HandlerType); logMessage.AppendLine(); } result.Add(eventType, eventHandlers); } Log.Debug(logMessage.ToString); return result; }
/// <summary> /// Discover all event handlers methods associated with any locatable class marked with with <see cref="EventHandlerAttribute"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator use to retrieve all known classes marked with <see cref="EventHandlerAttribute"/>.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> private static Dictionary<Type, List<EventHandler>> DiscoverHandleMethods(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy<IPublishCommands> commandPublisher) { var handlerTypes = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.GetCustomAttribute<EventHandlerAttribute>() != null); var knownEventHandlers = new Dictionary<Type, List<EventHandler>>(); foreach (var handlerType in handlerTypes) { var handleMethods = GetHandleMethods(handlerType, serviceProvider); var sagaMetadata = typeof(Saga).IsAssignableFrom(handlerType) ? GetSagaMetadata(handlerType, handleMethods) : null; foreach (var handleMethod in handleMethods) { List<EventHandler> eventHandlers; Type eventType = handleMethod.Key; if (!knownEventHandlers.TryGetValue(eventType, out eventHandlers)) knownEventHandlers.Add(eventType, eventHandlers = new List<EventHandler>()); var eventHandler = new EventHandler(handlerType, eventType, handleMethod.Value, GetHandlerFactory(handlerType, serviceProvider)); if (sagaMetadata != null) eventHandler = eventType == typeof(Timeout) ? new SagaTimeoutHandler(eventHandler, sagaMetadata, sagaStore, commandPublisher) : new SagaEventHandler(eventHandler, sagaMetadata, sagaStore, commandPublisher); eventHandlers.Add(eventHandler); } } return knownEventHandlers; }
public IStream Persistent(string reference, string category, ILocateTypes typeLocator) { return new MemoryStream(_eventStore); }
public IStream CatchUp(string reference, ILocateTypes typeLocator) { return new MemoryStream(_eventStore); }
/// <summary> /// Initializes a new instance of <see cref="AggregateUpdater"/>. /// </summary> /// <param name="typeLocator"></param> public AggregateUpdater(ILocateTypes typeLocator) { Verify.NotNull(typeLocator, nameof(typeLocator)); knownApplyMethods = new ReadOnlyDictionary<Type, ApplyMethodCollection>(DiscoverAggregates(typeLocator)); }
/// <summary> /// Generate unique saga type identifiers for all locatable <see cref="Saga"/> types. /// </summary> /// <param name="typeLocator">The type locator use to retrieve all known <see cref="Saga"/> types.</param> private static Dictionary<Type, Guid> GetKnownSagas(ILocateTypes typeLocator) { var knownSagas = typeLocator.GetTypes(type => type.IsClass && !type.IsAbstract && type.DerivesFrom(typeof(Saga))).ToDictionary(type => type, HashType); var logMessage = new StringBuilder(); logMessage.AppendLine("Discovered sagas:"); foreach (var saga in knownSagas) { logMessage.Append(" "); logMessage.AppendFormat("{0} - {1}", saga.Key, saga.Value); logMessage.AppendLine(); } Log.Debug(logMessage.ToString); return knownSagas; }
/// <summary> /// Discover all command handlers methods associated with any locatable <see cref="Aggregate"/> type. /// </summary> /// <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, HandleMethodCollection> DiscoverHandleMethods(ILocateTypes typeLocator, IServiceProvider serviceProvider) { var aggregateTypes = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.DerivesFrom(typeof(Aggregate))); var knownCommandHandlers = new Dictionary<Type, HandleMethodCollection>(); foreach (var aggregateType in aggregateTypes) { var handleMethods = GetHandleMethods(aggregateType, serviceProvider); knownCommandHandlers.Add(aggregateType, handleMethods); } return knownCommandHandlers; }
public IStream CatchUp(string streamName, ILocateTypes typeLocator) { return _stream; }
public IStream Persistent(string streamName, string groupName, ILocateTypes typeLocator) { return _stream; }
/// <summary> /// Initializes a new instance of <see cref="AggregateUpdater"/>. /// </summary> /// <param name="typeLocator"></param> public AggregateUpdater(ILocateTypes typeLocator) { Verify.NotNull(typeLocator, nameof(typeLocator)); knownApplyMethods = new ReadOnlyDictionary <Type, ApplyMethodCollection>(DiscoverAggregates(typeLocator)); }