public static void MapAggregate(IBoundedContextModel contextMap, Type aggregateType) { var methods = aggregateType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); foreach (var method in methods) { var parameters = method.GetParameters(); if (parameters.Count() == 1 && parameters[0].ParameterType.Namespace != null && parameters[0].ParameterType.Namespace.StartsWith(aggregateType.Namespace) && method.Name == "When") { if (methods.Any(m => m.Name == "Then" && m.GetParameters().FirstOrDefault(p => p.ParameterType == method.ReturnType) != null)) { CallGenericMethod(nameof(ApplyCommandHandlerToContextMap), contextMap, aggregateType, method.ReturnType, parameters); } else { var eventTypes = methods.Where(m => m.Name == "Then" && m.GetParameters().Count() == 1).Select(m => m.GetParameters().Single().ParameterType); var returnTypeProperties = method.ReturnType.GetProperties(BindingFlags.Public | BindingFlags.Instance); if (returnTypeProperties.All(p => eventTypes.Contains(p.PropertyType))) { returnTypeProperties.Select(p => p.PropertyType).ToList().ForEach(t => CallGenericMethod(nameof(ApplyCommandHandlerToContextMap), contextMap, aggregateType, t, parameters)); } } } } }
/// <summary> /// Eventhandlers are identified by not being aggregates and having method(s): /// named When /// with a single parameter that is a known event type and returns a command /// </summary> /// <param name="publicTypes"></param> public static void MapEventHandlers(IBoundedContextModel contextMap, IEnumerable <Type> publicTypes) { foreach (var publicType in publicTypes) { MapEventHandler(contextMap, publicType); } }
/// <summary> /// Creates a new instance of a domain engine for processing commands and optionly event handlers from a single bounded context. By default the engine will process a command /// handler & aggregate root for a command and return any events generated by the aggregate. /// </summary> /// <param name="boundedContextModel">Describes the static model of the domain. Include the command handlers and any event handlers to be executed in process.</param> /// <param name="eventStore">The event store used for event persistence by both command and event handers.</param> /// <param name="options">Options relating to the domain engine exection.</param> public DomainEngine(IBoundedContextModel boundedContextModel, IEventStore eventStore, DomainOptions options) { this.boundedContextModel = boundedContextModel; this.runtimeModel = new RuntimeModel(boundedContextModel, eventStore); this.commandHandler = new CommandHandler(boundedContextModel, runtimeModel); this.domainOptions = options; }
/// <summary> /// Aggregates are identified by having method(s) that: /// are named "When" /// have a single parameter /// with a type from the same or child namespace /// and a matching method named Then whos parameter is the same as the return type of the When method /// </summary> public static void MapAggregates(IBoundedContextModel contextMap, IEnumerable <Type> publicTypes) { foreach (var publicType in publicTypes) { MapAggregate(contextMap, publicType); } }
/// <summary> /// Creates a domin execution instance that can fully process command handlers and any configured event handlers /// including recursive handling of any commands generated by process managers. /// </summary> /// <param name="boundedContextModel">Describes the static model of the domain. Include the command handlers and any event handlers to be executed in process.</param> /// <param name="eventStore">The event store used for event persistence by both command and event handers.</param> /// <param name="eventQueueWriter">An event sink for writing the event output to a queue or similiar from within the command processing transaction.</param> /// <param name="isRuntimeModelCached">Is the runtime moel cached between calls, only set this true for single instance deployments.</param> /// <returns>Domain inteface for processing commands.</returns> public static IDomainEngine CreateDomainExecutionEngine(IBoundedContextModel boundedContextModel, IEventStore eventStore, IEventQueueWriter eventQueueWriter, DomainOptions options) { return(new DomainEngine(boundedContextModel, eventStore, options).WithEventBroker().WithEventQueue(eventQueueWriter)); //var domainEngine = new DomainExecutionEngine(boundedContextModel, eventStore).WithEventQueue(eventQueueWriter); //domainEngine.IsRuntimeModelCached = isRuntimeModelCached; //return domainEngine; }
public static IBoundedContextModel WithAllAppDomainAssemblies(this IBoundedContextModel contextMap) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies.Where(a => !a.IsDynamic)) { contextMap.WithAssembly(assembly, null); } return(contextMap); }
public static IBoundedContextModel WithAssembly(this IBoundedContextModel contextMap, Assembly assembly, string contextNamespace) { if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } AutoConfigure.FromAssembly(contextMap, assembly, contextNamespace); return(contextMap); }
public static IBoundedContextModel WithAssembly(this IBoundedContextModel contextMap, string assemblyName, string contextNamespace = null) { var assembly = Assembly.Load(assemblyName); if (assembly.IsDynamic) { throw new ArgumentException("Dynamic assemblies are not supported."); } contextMap.WithAssembly(assembly, contextNamespace); return(contextMap); }
public static void FromAssembly(IBoundedContextModel contextMap, Assembly assembly, string contextNamespace) { if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } var publicTypes = contextNamespace == null?assembly.GetExportedTypes() : assembly.GetExportedTypes().Where(t => t.Namespace.StartsWith(contextNamespace)); AutoConfigure.MapAggregates(contextMap, publicTypes); var allPublicTypesExceptAggregates = publicTypes.Where(t => !contextMap.IsAggregateType(t)).Distinct(); AutoConfigure.MapEventHandlers(contextMap, allPublicTypesExceptAggregates); }
private static void CallGenericMethod(string methodName, IBoundedContextModel contextMap, Type publicType, Type returnType, ParameterInfo[] parameters) { MethodInfo applyToContextMapInfo = typeof(AutoConfigure).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic); MethodInfo genericMethod; if (returnType == typeof(void)) { genericMethod = applyToContextMapInfo.MakeGenericMethod(parameters[0].ParameterType, publicType); } else { genericMethod = applyToContextMapInfo.MakeGenericMethod(parameters[0].ParameterType, publicType, returnType); } genericMethod.Invoke(null, new object[] { contextMap }); }
public static void MapEventHandler(IBoundedContextModel contextMap, Type eventHandlerType) { var methods = eventHandlerType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); foreach (var method in methods.Where(m => m.Name == "When")) { var parameters = method.GetParameters(); if (parameters.Count() == 1 && contextMap.IsEventType(parameters[0].ParameterType)) { if (method.ReturnType != null && contextMap.IsCommandType(method.ReturnType)) { CallGenericMethod(nameof(ApplyProcessHandlerToContextMap), contextMap, eventHandlerType, method.ReturnType, parameters); } else { CallGenericMethod(nameof(ApplyEventHandlerToContextMap), contextMap, eventHandlerType, typeof(void), parameters); } } } }
public DomainBroker(IBoundedContextModel boundedContextModel, IEventHandler eventHandler, ICommandHandler commandHandler) { if (boundedContextModel == null) { throw new ArgumentNullException(nameof(boundedContextModel)); } if (eventHandler == null) { throw new ArgumentNullException(nameof(eventHandler)); } if (commandHandler == null) { throw new ArgumentNullException(nameof(commandHandler)); } this.boundedContextModel = boundedContextModel; this.eventHandler = eventHandler; this.commandHandler = commandHandler; }
/// <summary> /// Creates a domain command engine that processes command handlers and returns any events created. /// </summary> /// <param name="boundedContextModel">Describes the static model of the domain. Any defined event handlers will be ignored.</param> /// <param name="eventStore">The event store used for event persistence by command handlers.</param> /// <returns>Domain inteface for processing commands.</returns> public static IDomainEngine CreateCommandEngine(IBoundedContextModel boundedContextModel, IEventStore eventStore) { return(new DomainEngine(boundedContextModel, eventStore, DomainOptions.Defaults)); }
/// <summary> /// Created a dispatcher for domain events that can one way dispatch events to any defined event handlers. /// </summary> /// <param name="boundedContextModel">Describes the static model of the domain. Only event handler definitions are used for determining the event handlers that need to b e called.</param> /// <param name="eventHandler">The event handler instance to receive events. This will be called once per event for each defined event handler.</param> /// <returns>Domain inteface for dispatching events.</returns> public static IEventDispatcher CreateEventDispatcher(IBoundedContextModel boundedContextModel, IEventHandler eventHandler) { return(new EventDispatcher(boundedContextModel, eventHandler)); }
public CommandHandler(IBoundedContextModel contextModel, IRuntimeModel runtimeModel) { this.contextModel = contextModel; this.runtimeModel = runtimeModel; }
public EventHandlerAdapter(TEventHandler eventHandler, IBoundedContextModel contextMap) { this.eventHandler = eventHandler; this.contextMap = contextMap; this.eventHandlerModel = this.contextMap.EventHandlerModel(typeof(TEventHandler)); }
/// <summary> /// Creates a domain event engine for processing an event handler. /// </summary> /// <param name="boundedContextModel">Describes the static model of the domain. Only event handler definitions are used for the processing of events.</param> /// <param name="eventStore">The event store used to store any events handled by event handlers to ensure idempotency.</param> /// <returns>Domain inteface for processing events.</returns> public static IEventHandler CreateEventHandler(IBoundedContextModel boundedContextModel, IEventStore eventStore) { return(new TransactionalEventHandler(boundedContextModel, eventStore, cacheRuntimeModel: false)); }
private static void ApplyEventHandlerToContextMap <TEvent, TEventHandler>(IBoundedContextModel contextMap) where TEventHandler : class { contextMap.WithEventHandler <TEvent, TEventHandler>((e) => e.Id); }
internal AggregateAdapter(IBoundedContextModel contextMap, TAggregateRoot aggregateRoot, int version) : this(contextMap, aggregateRoot) { this.version = version; }
public IEventHandlerAdapter <TProcess> CreateEventHandler <TProcess>(string id, TProcess process, IBoundedContextModel contextMap) { return(new EventHandlerAdapter <TProcess>(process, contextMap).WithId(id)); }
public RuntimeAggregateModel(IBoundedContextModel contextMap, IEventStore eventStore) { this.contextMap = contextMap; this.eventStore = eventStore; this.snapshotRepository = eventStore as ISnapshotRepository; }
public IAggregateAdapter <TAggregate> CreateAggregate <TAggregate>(IBoundedContextModel contextMap, TAggregate aggregate, int version) { return(new AggregateAdapter <TAggregate>(contextMap, aggregate, version)); }
internal TransactionalEventHandler(IBoundedContextModel boundedContextModel, IEventStore eventStore, bool cacheRuntimeModel) { this.runtimeModel = new RuntimeModel(boundedContextModel, eventStore); this.eventHandler = new EventHandler(boundedContextModel, runtimeModel); this.cacheRuntimeModel = cacheRuntimeModel; }
public EventDispatcher(IBoundedContextModel boundedContextModel, IEventHandler eventHandler) { this.boundedContextModel = boundedContextModel; this.eventHandler = eventHandler; }
public RuntimeModel(IBoundedContextModel contextMap, IEventStore eventStore) { this.aggregates = new RuntimeAggregateModel(contextMap, eventStore); this.eventHandlers = new RuntimeEventHandlerModel(contextMap, eventStore); }
private static void ApplyProcessHandlerToContextMap <TEvent, TEventHandler, TCommand>(IBoundedContextModel contextMap) where TEventHandler : class { contextMap.WithEventHandler <TEvent, TEventHandler, TCommand>((e) => e.Id, c => c.GetType().GetProperties().First().GetValue(c).ToString()); }
/// <summary> /// Creates a domain command engine for processing command handlers that returns any events created as well as passing them to any defined event /// handlers while within the same transaction scope. It is the responsibility of the event handers to further dispatch any commands they raise. /// </summary> /// <param name="boundedContextModel">Describes the static model of the domain. Event handler definitions are used to determine the event handlers to call.</param> /// <param name="eventStore">The event store used for event persistence by command handlers.</param> /// <param name="eventHandler">The event handler instance to receive events. This will be called once per event for each defined event handler.</param> /// <returns>Domain inteface for processing commands.</returns> public static IDomainEngine CreateCommandEngine(IBoundedContextModel boundedContextModel, IEventStore eventStore, IEventHandler eventHandler) { return(new DomainEngine(boundedContextModel, eventStore, DomainOptions.Defaults).WithEventDispatcher(new EventDispatcher(boundedContextModel, eventHandler))); }
internal AggregateAdapter(IBoundedContextModel contextMap, TAggregateRoot aggregateRoot) { this.contextMap = contextMap; this.aggregateRoot = aggregateRoot; this.aggregateModel = contextMap.AggregateModel(typeof(TAggregateRoot)); }
public RuntimeEventHandlerModel(IBoundedContextModel contextMap, IEventStore eventStore) { this.contextMap = contextMap; this.eventStore = eventStore; }
private static void ApplyCommandHandlerToContextMap <TCommand, TAggregate, TEvent>(IBoundedContextModel contextMap) { contextMap.WithCommandHandler <TCommand, TAggregate, TEvent>(); }