using Microsoft.EntityFrameworkCore; using Quartz; namespace NejCommon; public interface IScopedService { } public interface ISingletonService { } public interface ITransientService { } public interface IBackgroundService { } public interface IRecurringService : IJob { public static virtual JobKey? JobKey { get; } public static abstract string Cron { get; } } public interface ISettings { string Path { get; } } public static class AutoScan { public static void RegisterJobs(this IServiceCollection collection, IServiceCollectionQuartzConfigurator conf) { var jobs = typeof(IRecurringService).Assembly.GetTypes().Where(x => x.IsAssignableTo(typeof(IRecurringService)) && x != typeof(IRecurringService)).ToList(); foreach (var job in jobs) { Console.WriteLine("Testing job: " + job.Name); var jobKey = job.GetProperty("JobKey")?.GetValue(null) as JobKey ?? new JobKey(job.FullName); var cron = job.GetProperty("Cron")!.GetValue(null) as string; if (string.IsNullOrEmpty(cron) || jobKey == null) { throw new Exception("Could not register job: " + job.Name); } Console.WriteLine("Adding job: " + jobKey.Name + " with cron: " + cron); conf.AddJob(job, jobKey).AddTrigger(x => x.ForJob(jobKey).WithCronSchedule(cron).StartNow()); } } public static void RegisterServices(this IServiceCollection collection) { collection.Scan(scan => scan // We start out with all types in the assembly of ITransientService .FromAssemblyOf() // AddClasses starts out with all public, non-abstract types in this assembly. // These types are then filtered by the delegate passed to the method. // In this case, we filter out only the classes that are assignable to ITransientService. .AddClasses(classes => classes.AssignableTo()) // We then specify what type we want to register these classes as. // In this case, we want to register the types as all of its implemented interfaces. // So if a type implements 3 interfaces; A, B, C, we'd end up with three separate registrations. .AsSelf() // And lastly, we specify the lifetime of these registrations. .WithTransientLifetime() // Here we start again, with a new full set of classes from the assembly above. // This time, filtering out only the classes assignable to IScopedService. .AddClasses(classes => classes.AssignableTo()) // Now, we just want to register these types as a single interface, IScopedService. .AsSelf() // And again, just specify the lifetime. .WithScopedLifetime() .AddClasses(classes => classes.AssignableTo()) .AsSelf() .AsImplementedInterfaces() .WithSingletonLifetime() .AddClasses(classes => classes.AssignableTo()) .AsSelf() .AsImplementedInterfaces() .WithSingletonLifetime() ); } }