public FindRunHandlers(IServiceProvider serviceProvider, ILogger logger, IGenericEventRunnerConfig config) { _serviceProvider = serviceProvider; _logger = logger; _config = config; _findHandlers = new FindHandlers(serviceProvider, logger); }
/// <summary> /// This register the Generic EventRunner and the various event handlers you have created in the assemblies you provide. /// </summary> /// <param name="services"></param> /// <param name="config">A GenericEventRunnerConfig instance with your own settings.</param> /// <param name="assembliesToScan">Series of assemblies to scan. If not provided then scans the calling assembly</param> public static void RegisterGenericEventRunner(this IServiceCollection services, IGenericEventRunnerConfig config, params Assembly[] assembliesToScan) { if (config == null) { throw new ArgumentNullException(nameof(config)); } if (!assembliesToScan.Any()) { assembliesToScan = new Assembly[] { Assembly.GetCallingAssembly() } } ; var eventHandlersToRegister = new List <(Type classType, Type interfaceType)>(); var someAfterSaveHandlersFound = false; foreach (var assembly in assembliesToScan) { eventHandlersToRegister.AddRange(ClassesWithGivenEventHandlerType(typeof(IBeforeSaveEventHandler <>), assembly)); var count = eventHandlersToRegister.Count; if (!config.NotUsingAfterSaveHandlers) { eventHandlersToRegister .AddRange(ClassesWithGivenEventHandlerType(typeof(IAfterSaveEventHandler <>), assembly)); } someAfterSaveHandlersFound |= (eventHandlersToRegister.Count > count); } if (!someAfterSaveHandlersFound) { config.NotUsingAfterSaveHandlers = true; } foreach (var(implementationType, interfaceType) in eventHandlersToRegister) { var attr = implementationType.GetCustomAttribute <EventHandlerConfigAttribute>(); var lifeTime = attr?.HandlerLifetime ?? ServiceLifetime.Transient; if (lifeTime == ServiceLifetime.Transient) { services.AddTransient(interfaceType, implementationType); } else if (lifeTime == ServiceLifetime.Scoped) { services.AddScoped(interfaceType, implementationType); } else { services.AddSingleton(interfaceType, implementationType); } } services.AddSingleton <IGenericEventRunnerConfig>(config); services.AddScoped <IEventsRunner, EventsRunner>(); }
/// <summary> /// This is the class that will manage the events inside your DbContext /// </summary> /// <param name="serviceProvider"></param> /// <param name="logger"></param> /// <param name="config"></param> public EventsRunner(IServiceProvider serviceProvider, ILogger <EventsRunner> logger, IGenericEventRunnerConfig config) { _config = config ?? throw new ArgumentNullException(nameof(config)); _findRunHandlers = new FindRunHandlers(serviceProvider, logger, _config); }
/// <summary> /// This register the Generic EventRunner and the various event handlers you have created in the assemblies you provide. /// </summary> /// <param name="services"></param> /// <param name="config">A GenericEventRunnerConfig instance with your own settings.</param> /// <param name="assembliesToScan">Series of assemblies to scan. If not provided then scans the calling assembly</param> /// <returns>List of what it registered - useful for debugging</returns> public static List <string> RegisterGenericEventRunner(this IServiceCollection services, IGenericEventRunnerConfig config, params Assembly[] assembliesToScan) { var debugLogs = new List <string>(); if (config == null) { throw new ArgumentNullException(nameof(config)); } if (!assembliesToScan.Any()) { assembliesToScan = new Assembly[] { Assembly.GetCallingAssembly() }; debugLogs.Add("No assemblies provided so only scanning calling assembly."); } var someDuringSaveHandlersFound = false; var someAfterSaveHandlersFound = false; foreach (var assembly in assembliesToScan) { debugLogs.Add($"Starting scanning assembly {assembly.GetName().Name} for event handlers."); services.RegisterHandlersIfNotAlreadyRegistered(debugLogs, typeof(IBeforeSaveEventHandler <>), assembly); services.RegisterHandlersIfNotAlreadyRegistered(debugLogs, typeof(IBeforeSaveEventHandlerAsync <>), assembly); if (!config.NotUsingDuringSaveHandlers) { someDuringSaveHandlersFound |= services.RegisterHandlersIfNotAlreadyRegistered(debugLogs, typeof(IDuringSaveEventHandler <>), assembly); someDuringSaveHandlersFound |= services.RegisterHandlersIfNotAlreadyRegistered(debugLogs, typeof(IDuringSaveEventHandlerAsync <>), assembly); } if (!config.NotUsingAfterSaveHandlers) { someAfterSaveHandlersFound |= services.RegisterHandlersIfNotAlreadyRegistered(debugLogs, typeof(IAfterSaveEventHandler <>), assembly); someAfterSaveHandlersFound |= services.RegisterHandlersIfNotAlreadyRegistered(debugLogs, typeof(IAfterSaveEventHandlerAsync <>), assembly); } } if (!someDuringSaveHandlersFound) { debugLogs.Add(config.NotUsingDuringSaveHandlers ? "You manually turned off During event handlers." : "No During event handlers were found, so turned that part off."); config.NotUsingDuringSaveHandlers = true; } if (!someAfterSaveHandlersFound) { debugLogs.Add(config.NotUsingAfterSaveHandlers ? "You manually turned off After event handlers." : "No After event handlers were found, so turned that part off."); config.NotUsingAfterSaveHandlers = true; } if (services.Contains(new ServiceDescriptor(typeof(IEventsRunner), typeof(EventsRunner), ServiceLifetime.Transient), new ServiceDescriptorNoLifeTimeCompare())) { throw new InvalidOperationException("You can only call this method once to register the GenericEventRunner and event handlers."); } services.AddSingleton <IGenericEventRunnerConfig>(config); services.AddTransient <IEventsRunner, EventsRunner>(); debugLogs.Add($"Finished by registering the {nameof(EventsRunner)} and {nameof(GenericEventRunnerConfig)}"); return(debugLogs); }
/// <summary> /// This is the class that will manage the events inside your DbContext /// </summary> /// <param name="serviceProvider"></param> /// <param name="logger"></param> /// <param name="config"></param> public EventsRunner(IServiceProvider serviceProvider, ILogger <EventsRunner> logger, IGenericEventRunnerConfig config) { _config = config ?? throw new ArgumentNullException(nameof(config)); _eachEventRunner = new RunEachTypeOfEvents(serviceProvider, logger, _config); }
/// <summary> /// This extension method provides a way to set up a DbContext with an EventsRunner and also registers all /// the event handlers in the assembly that the TRunner class is in. /// </summary> /// <typeparam name="TContext">Your DbContext type</typeparam> /// <typeparam name="THandler">The type of one of your event handlers. /// The whole assembly that the TRunner is in will be scanned for event handlers</typeparam> /// <param name="options">The <code>T:DbContextOptions{TContext}</code> for your DbContext</param> /// <param name="logs">Optional. If provided the it uses the EfCore.TestSupport logging provider to return logs</param> /// <param name="config">Optional. Allows you to change the configuration setting for GenericEventRunner</param> /// <returns>An instance of the DbContext created by DI and therefore containing the EventsRunner</returns> public static TContext CreateDbWithDiForHandlers <TContext, THandler>(this DbContextOptions <TContext> options, List <LogOutput> logs = null, IGenericEventRunnerConfig config = null) where TContext : DbContext where THandler : class { var services = new ServiceCollection(); if (logs != null) { services.AddSingleton <ILogger <EventsRunner> >(new Logger <EventsRunner>(new LoggerFactory(new[] { new MyLoggerProviderActionOut(logs.Add) }))); } else { services.AddSingleton <ILogger <EventsRunner> >(new NullLogger <EventsRunner>()); } var assembliesToScan = new Assembly[] { Assembly.GetAssembly(typeof(THandler)), Assembly.GetExecutingAssembly() //This will pick up any event handlers in your unit tests assembly }; services.RegisterGenericEventRunner(config ?? new GenericEventRunnerConfig(), assembliesToScan); services.AddSingleton(options); services.AddScoped <TContext>(); var serviceProvider = services.BuildServiceProvider(); var context = serviceProvider.GetRequiredService <TContext>(); return(context); }
public static ExampleDbContext CreateAndSeedDbWithDiForHandlers <TRunner>(this DbContextOptions <ExampleDbContext> options, List <LogOutput> logs = null, IGenericEventRunnerConfig config = null) where TRunner : class { var context = options.CreateDbWithDiForHandlers <ExampleDbContext, TRunner>(logs, config); context.Database.EnsureCreated(); context.SeedTaxAndStock(); return(context); }
/// <summary> /// This is the class that will manage the events inside your DbContext /// </summary> /// <param name="serviceProvider"></param> /// <param name="logger"></param> /// <param name="config"></param> public EventsRunner(IServiceProvider serviceProvider, ILogger <EventsRunner> logger, IGenericEventRunnerConfig config) { _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _config = config ?? throw new ArgumentNullException(nameof(config)); }