├── src └── QuartzHostedService │ ├── AssemblyInfo.cs │ ├── IJobRegistrator.cs │ ├── JobOptions.cs │ ├── IScheduleJob.cs │ ├── JobRegistrator.cs │ ├── ScheduleJob.cs │ ├── TriggerOptions.cs │ ├── Properties │ └── launchSettings.json │ ├── QuartzHostedService.csproj │ ├── ServiceCollectionJobFactory.cs │ ├── QuartzHostedService.cs │ ├── IServiceCollectionExtensions.cs │ └── IJobRegistratorExtensions.cs ├── sample ├── AspNetCoreSampleQuartzHostedService │ ├── appsettings.json │ ├── InjectProperty.cs │ ├── appsettings.Development.json │ ├── AppSettings.cs │ ├── Jobs │ │ ├── HelloJob.cs │ │ ├── HelloJobSingle.cs │ │ ├── InjectSampleJob.cs │ │ └── InjectSampleJobSingle.cs │ ├── AspNetCoreSampleQuartzHostedService.csproj │ ├── Properties │ │ └── launchSettings.json │ ├── Program.cs │ ├── Controllers │ │ └── ValuesController.cs │ └── Startup.cs └── SampleQuartzHostedService │ ├── InjectProperty.cs │ ├── Jobs │ ├── HelloJob.cs │ └── InjectSampleJob.cs │ ├── SampleQuartzHostedService.csproj │ └── Program.cs ├── test └── QuartzHostedService.Test │ ├── IServiceCollectionExtensionsUnitTest.cs │ ├── QuartzHostedService.Test.csproj │ └── QuartzHostedServiceUnitTest.cs ├── .travis.yml ├── README.md ├── .gitattributes ├── .gitignore └── QuartzHostedService.sln /src/QuartzHostedService/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("QuartzHostedService.Test")] -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning" 5 | } 6 | }, 7 | "AllowedHosts": "*" 8 | } 9 | -------------------------------------------------------------------------------- /test/QuartzHostedService.Test/IServiceCollectionExtensionsUnitTest.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mukmyash/QuartzHostedService/HEAD/test/QuartzHostedService.Test/IServiceCollectionExtensionsUnitTest.cs -------------------------------------------------------------------------------- /src/QuartzHostedService/IJobRegistrator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace QuartzHostedService 4 | { 5 | public interface IJobRegistrator 6 | { 7 | IServiceCollection Services { get; } 8 | } 9 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | sudo: required 3 | dist: xenial 4 | mono: none 5 | dotnet: 3.0 6 | before_script: 7 | - dotnet restore 8 | script: 9 | - dotnet test ./test/QuartzHostedService.Test -c Release 10 | - dotnet build -c Release -------------------------------------------------------------------------------- /src/QuartzHostedService/JobOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace QuartzHostedService 6 | { 7 | public class JobOptions 8 | { 9 | public TriggerOptions[] Triggers { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /sample/SampleQuartzHostedService/InjectProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SampleQuartzHostedService 6 | { 7 | public class InjectProperty 8 | { 9 | public string WriteText { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/QuartzHostedService/IScheduleJob.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Quartz; 3 | 4 | namespace QuartzHostedService 5 | { 6 | internal interface IScheduleJob 7 | { 8 | IJobDetail JobDetail { get; set; } 9 | IEnumerable Triggers { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/InjectProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace AspNetCoreSampleQuartzHostedService 6 | { 7 | public class InjectProperty 8 | { 9 | public string WriteText { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | }, 9 | "EnableHelloJob": true, 10 | "EnableHelloSingleJob": true 11 | 12 | } 13 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/AppSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace AspNetCoreSampleQuartzHostedService 7 | { 8 | public class AppSettings 9 | { 10 | public bool EnableHelloJob { get; set; } 11 | public bool EnableHelloSingleJob { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sample/SampleQuartzHostedService/Jobs/HelloJob.cs: -------------------------------------------------------------------------------- 1 | using Quartz; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace SampleQuartzHostedService.Jobs 8 | { 9 | public class HelloJob : IJob 10 | { 11 | public Task Execute(IJobExecutionContext context) 12 | { 13 | Console.WriteLine("Hello"); 14 | return Task.CompletedTask; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/QuartzHostedService/JobRegistrator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace QuartzHostedService 7 | { 8 | internal class JobRegistrator : IJobRegistrator 9 | { 10 | public JobRegistrator(IServiceCollection services) 11 | { 12 | Services = services; 13 | } 14 | 15 | public IServiceCollection Services { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/Jobs/HelloJob.cs: -------------------------------------------------------------------------------- 1 | using Quartz; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AspNetCoreSampleQuartzHostedService.Jobs 8 | { 9 | public class HelloJob : IJob 10 | { 11 | public Task Execute(IJobExecutionContext context) 12 | { 13 | Console.WriteLine("Hello"); 14 | return Task.CompletedTask; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/AspNetCoreSampleQuartzHostedService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/Jobs/HelloJobSingle.cs: -------------------------------------------------------------------------------- 1 | using Quartz; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AspNetCoreSampleQuartzHostedService.Jobs 8 | { 9 | public class HelloJobSingle : IJob 10 | { 11 | public Task Execute(IJobExecutionContext context) 12 | { 13 | Console.WriteLine("Hello Single"); 14 | return Task.CompletedTask; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/QuartzHostedService/ScheduleJob.cs: -------------------------------------------------------------------------------- 1 | using Quartz; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace QuartzHostedService 6 | { 7 | internal class ScheduleJob : IScheduleJob 8 | { 9 | public ScheduleJob(IJobDetail jobDetail, IEnumerable triggers) 10 | { 11 | JobDetail = jobDetail; 12 | Triggers = triggers; 13 | } 14 | 15 | public IJobDetail JobDetail { get; set; } 16 | public IEnumerable Triggers { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/SampleQuartzHostedService/SampleQuartzHostedService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /sample/SampleQuartzHostedService/Jobs/InjectSampleJob.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | using Quartz; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SampleQuartzHostedService.Jobs 9 | { 10 | public class InjectSampleJob : IJob 11 | { 12 | InjectProperty _options; 13 | 14 | public InjectSampleJob(IOptions options) 15 | { 16 | _options = options.Value; 17 | } 18 | public Task Execute(IJobExecutionContext context) 19 | { 20 | Console.WriteLine(_options.WriteText); 21 | return Task.CompletedTask; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/Jobs/InjectSampleJob.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | using Quartz; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AspNetCoreSampleQuartzHostedService.Jobs 9 | { 10 | public class InjectSampleJob : IJob 11 | { 12 | InjectProperty _options; 13 | 14 | public InjectSampleJob(IOptions options) 15 | { 16 | _options = options.Value; 17 | } 18 | public Task Execute(IJobExecutionContext context) 19 | { 20 | Console.WriteLine(_options.WriteText); 21 | return Task.CompletedTask; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/QuartzHostedService/TriggerOptions.cs: -------------------------------------------------------------------------------- 1 | using Quartz; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace QuartzHostedService 7 | { 8 | public class TriggerOptions 9 | { 10 | public string CRONExpression { get; set; } 11 | 12 | public int? Priority { get; set; } 13 | 14 | public virtual TriggerBuilder CreateTriggerBuilder() 15 | { 16 | var result = TriggerBuilder.Create(); 17 | if (Priority.HasValue) 18 | result.WithPriority(Priority.Value); 19 | 20 | if(!string.IsNullOrEmpty(CRONExpression)) 21 | result.WithCronSchedule(CRONExpression); 22 | 23 | return result; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/Jobs/InjectSampleJobSingle.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | using Quartz; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AspNetCoreSampleQuartzHostedService.Jobs 9 | { 10 | public class InjectSampleJobSingle : IJob 11 | { 12 | InjectProperty _options; 13 | 14 | public InjectSampleJobSingle(IOptions options) 15 | { 16 | _options = options.Value; 17 | } 18 | public Task Execute(IJobExecutionContext context) 19 | { 20 | Console.WriteLine($"InjectSampleJobSingle {_options.WriteText} "); 21 | return Task.CompletedTask; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/QuartzHostedService/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:56070/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "QuartzHostedService": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:56071/" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/QuartzHostedService/QuartzHostedService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | mukmyash 6 | 7 | 0.0.7 8 | true 9 | https://github.com/mukmyash/QuartzHostedService 10 | Wrapper above [Quartz.NET] (https://github.com/quartznet/quartznet) for .NET Core. 11 | scheduling tasks jobs triggers scheduler threading quartz 12 | QuartzHostedService 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:55225", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "api/values", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "AspNetCoreSampleQuartzHostedService": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "api/values", 24 | "applicationUrl": "http://localhost:5000", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/QuartzHostedService.Test/QuartzHostedService.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Microsoft.Extensions.Hosting; 11 | using Microsoft.Extensions.Logging; 12 | using QuartzHostedService; 13 | 14 | namespace AspNetCoreSampleQuartzHostedService 15 | { 16 | public class Program 17 | { 18 | public static void Main(string[] args) 19 | { 20 | CreateHostBuilder(args).Build().Run(); 21 | } 22 | 23 | public static IHostBuilder CreateHostBuilder(string[] args) => 24 | Host.CreateDefaultBuilder(args) 25 | .ConfigureWebHostDefaults(webBuilder => 26 | { 27 | webBuilder.UseStartup(); 28 | webBuilder.ConfigureKestrel(serverOptions => 29 | { 30 | serverOptions.AllowSynchronousIO = true; 31 | }); 32 | }) 33 | .ConfigureQuartzHost(); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/Controllers/ValuesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AspNetCoreSampleQuartzHostedService.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | [ApiController] 11 | public class ValuesController : ControllerBase 12 | { 13 | // GET api/values 14 | [HttpGet] 15 | public ActionResult> Get() 16 | { 17 | return new string[] { "value1", "value2" }; 18 | } 19 | 20 | // GET api/values/5 21 | [HttpGet("{id}")] 22 | public ActionResult Get(int id) 23 | { 24 | return "value"; 25 | } 26 | 27 | // POST api/values 28 | [HttpPost] 29 | public void Post([FromBody] string value) 30 | { 31 | } 32 | 33 | // PUT api/values/5 34 | [HttpPut("{id}")] 35 | public void Put(int id, [FromBody] string value) 36 | { 37 | } 38 | 39 | // DELETE api/values/5 40 | [HttpDelete("{id}")] 41 | public void Delete(int id) 42 | { 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/QuartzHostedService/ServiceCollectionJobFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Quartz; 3 | using Quartz.Spi; 4 | using System; 5 | using System.Collections.Concurrent; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace QuartzHostedService 10 | { 11 | public class ServiceCollectionJobFactory : IJobFactory 12 | { 13 | protected readonly IServiceProvider Container; 14 | private ConcurrentDictionary _createdJob = new ConcurrentDictionary(); 15 | 16 | public ServiceCollectionJobFactory(IServiceProvider container) 17 | { 18 | Container = container; 19 | } 20 | 21 | public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) 22 | { 23 | var scoped = Container.CreateScope(); 24 | var result = scoped.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob; 25 | _createdJob.AddOrUpdate(result, scoped, (j, s) => scoped); 26 | return result; 27 | } 28 | 29 | public void ReturnJob(IJob job) 30 | { 31 | if (_createdJob.TryRemove(job, out var scope)) 32 | { 33 | scope.Dispose(); 34 | } 35 | 36 | var disposable = job as IDisposable; 37 | disposable?.Dispose(); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /sample/SampleQuartzHostedService/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using Quartz; 4 | using QuartzHostedService; 5 | using SampleQuartzHostedService.Jobs; 6 | using System; 7 | using System.Threading.Tasks; 8 | using System.Collections.Generic; 9 | 10 | namespace SampleQuartzHostedService 11 | { 12 | public class Program 13 | { 14 | public static async Task Main(string[] args) 15 | { 16 | var hostBuilder = new HostBuilder() 17 | .ConfigureServices(services => 18 | { 19 | services.AddOptions(); 20 | services.Configure(options=> { options.WriteText = "This is inject string"; }); 21 | services.UseQuartzHostedService() 22 | .RegiserJob(() => 23 | { 24 | var result = new List(); 25 | result.Add(TriggerBuilder.Create() 26 | .WithSimpleSchedule(x=>x.WithIntervalInSeconds(1).RepeatForever())); 27 | result.Add(TriggerBuilder.Create() 28 | .WithSimpleSchedule(x => x.WithIntervalInSeconds(2).RepeatForever())); 29 | return result; 30 | }) 31 | .RegiserJob(() => 32 | { 33 | var result = new List(); 34 | result.Add(TriggerBuilder.Create() 35 | .WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever())); 36 | return result; 37 | }); 38 | }).ConfigureQuartzHost(); 39 | 40 | await hostBuilder.RunConsoleAsync(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuartzHostedService 2 | 3 | Wrapper above [Quartz.NET] (https://github.com/quartznet/quartznet) for .NET Core. 4 | 5 | ## Usage 6 | 7 | 1. Create Quartz-Job implements IJob interface 8 | 9 | ``` C# 10 | public class HelloJob : IJob 11 | { 12 | public Task Execute(IJobExecutionContext context) 13 | { 14 | Console.WriteLine("Hello"); 15 | return Task.CompletedTask; 16 | } 17 | } 18 | ``` 19 | 1. Call extension methode __UseQuartzHostedServic__ in *IServiceCollection* and register and configure your created job. 20 | ``` C# 21 | services.UseQuartzHostedService() 22 | .RegiserJob(() => 23 | { 24 | var result = new List(); 25 | result.Add(TriggerBuilder.Create() 26 | .WithSimpleSchedule(x=>x.WithIntervalInSeconds(1).RepeatForever())); 27 | result.Add(TriggerBuilder.Create() 28 | .WithSimpleSchedule(x => x.WithIntervalInSeconds(2).RepeatForever())); 29 | return result; 30 | }) 31 | ``` 32 | 1. ConfigureQuartzHost Must be call after Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults() 33 | 34 | ``` 35 | public class Program 36 | { 37 | public static void Main(string[] args) 38 | { 39 | CreateHostBuilder(args).Build().Run(); 40 | } 41 | 42 | public static IHostBuilder CreateHostBuilder(string[] args) => 43 | Host.CreateDefaultBuilder(args) 44 | .ConfigureWebHostDefaults(webBuilder => 45 | { 46 | webBuilder.UseStartup(); 47 | webBuilder.ConfigureKestrel(serverOptions => 48 | { 49 | serverOptions.AllowSynchronousIO = true; 50 | }); 51 | }) 52 | .ConfigureQuartzHost(); 53 | } 54 | ``` -------------------------------------------------------------------------------- /src/QuartzHostedService/QuartzHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Quartz.Impl; 9 | using Quartz; 10 | using Quartz.Spi; 11 | using System.Linq; 12 | 13 | namespace QuartzHostedService 14 | { 15 | internal class QuartzHostedService : IHostedService 16 | { 17 | private IServiceProvider Services { get; } 18 | private IScheduler _scheduler; 19 | private ISchedulerFactory _schedulerFactory; 20 | private IJobFactory _jobFactory { get; } 21 | 22 | public QuartzHostedService( 23 | IServiceProvider services, 24 | ISchedulerFactory schedulerFactory, 25 | IJobFactory jobFactory) 26 | { 27 | Services = services; 28 | _schedulerFactory = schedulerFactory; 29 | _jobFactory = jobFactory; 30 | } 31 | 32 | public async Task StartAsync(CancellationToken cancellationToken) 33 | { 34 | var _scheduleJobs = Services.GetService>(); 35 | 36 | _scheduler = await _schedulerFactory.GetScheduler(); 37 | _scheduler.JobFactory = _jobFactory; 38 | 39 | await _scheduler.Start(cancellationToken); 40 | 41 | if (_scheduleJobs == null || !_scheduleJobs.Any()) 42 | return; 43 | 44 | foreach (var scheduleJob in _scheduleJobs) 45 | { 46 | bool isNewJob = true; 47 | foreach (var trigger in scheduleJob.Triggers) 48 | { 49 | if (isNewJob) 50 | await _scheduler.ScheduleJob(scheduleJob.JobDetail, trigger, cancellationToken); 51 | else 52 | await _scheduler.ScheduleJob(trigger, cancellationToken); 53 | isNewJob = false; 54 | } 55 | } 56 | } 57 | 58 | public async Task StopAsync(CancellationToken cancellationToken) 59 | { 60 | if (_scheduler.IsStarted) 61 | await _scheduler.Shutdown(cancellationToken); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain -------------------------------------------------------------------------------- /src/QuartzHostedService/IServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Hosting; 4 | using Quartz; 5 | using Quartz.Impl; 6 | using Quartz.Spi; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Collections.Specialized; 10 | using System.Text; 11 | 12 | namespace QuartzHostedService 13 | { 14 | public static class IServiceCollectionExtensions 15 | { 16 | public static IJobRegistrator UseQuartzHostedService(this IServiceCollection services) 17 | { 18 | return UseQuartzHostedService(services, null); 19 | } 20 | public static IServiceCollection AddQuartzHostedService(this IServiceCollection services) 21 | { 22 | return AddQuartzHostedService(services, null); 23 | 24 | } 25 | public static IServiceCollection AddQuartzHostedService(this IServiceCollection services, 26 | Action stdSchedulerFactoryOptions) 27 | { 28 | var re = services.UseQuartzHostedService(stdSchedulerFactoryOptions); 29 | return re.Services; 30 | } 31 | 32 | private static bool _quartzHostedServiceIsAdded = false; 33 | /// 34 | /// Must be call after Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults() 35 | /// 36 | /// 37 | /// 38 | /// 39 | /// 40 | public static IHostBuilder ConfigureQuartzHost(this IHostBuilder builder) 41 | { 42 | _quartzHostedServiceIsAdded = true; 43 | return builder.ConfigureServices(services => services.AddHostedService()); 44 | } 45 | 46 | 47 | public static IJobRegistrator UseQuartzHostedService(this IServiceCollection services, 48 | Action stdSchedulerFactoryOptions) 49 | { 50 | if (!_quartzHostedServiceIsAdded) 51 | { 52 | services.AddHostedService(); 53 | } 54 | services.AddTransient(provider => 55 | { 56 | var options = new NameValueCollection(); 57 | stdSchedulerFactoryOptions?.Invoke(options); 58 | var result = new StdSchedulerFactory(); 59 | if (options.Count > 0) 60 | result.Initialize(options); 61 | return result; 62 | }); 63 | services.AddSingleton(); 64 | return new JobRegistrator(services); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /sample/AspNetCoreSampleQuartzHostedService/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using AspNetCoreSampleQuartzHostedService.Jobs; 6 | using CrystalQuartz.AspNetCore; 7 | using Microsoft.AspNetCore.Builder; 8 | using Microsoft.AspNetCore.Hosting; 9 | using Microsoft.AspNetCore.Mvc; 10 | using Microsoft.Extensions.Configuration; 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Hosting; 13 | using Microsoft.Extensions.Logging; 14 | using Microsoft.Extensions.Options; 15 | using Quartz; 16 | using QuartzHostedService; 17 | 18 | namespace AspNetCoreSampleQuartzHostedService 19 | { 20 | public class Startup 21 | { 22 | public Startup(IConfiguration configuration) 23 | { 24 | Configuration = configuration; 25 | } 26 | 27 | public IConfiguration Configuration { get; } 28 | 29 | // This method gets called by the runtime. Use this method to add services to the container. 30 | public void ConfigureServices(IServiceCollection services) 31 | { 32 | services.AddControllersWithViews(); 33 | services.AddOptions(); 34 | services.Configure(Configuration); 35 | services.Configure(options => { options.WriteText = "This is inject string"; }); 36 | services.AddQuartzHostedService() 37 | .AddQuartzJob() 38 | .AddQuartzJob() 39 | .AddQuartzJob() 40 | .AddQuartzJob(); 41 | } 42 | 43 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 44 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions settings, ISchedulerFactory factory) 45 | { 46 | if (env.IsDevelopment()) 47 | { 48 | app.UseDeveloperExceptionPage(); 49 | } 50 | app.UseRouting(); 51 | app.UseEndpoints(endpoint => 52 | { 53 | endpoint.MapControllers(); 54 | }); 55 | app.UseCrystalQuartz(() => factory.GetScheduler().Result); 56 | if (settings.Value.EnableHelloSingleJob) 57 | { 58 | app.UseQuartzJob(TriggerBuilder.Create().WithSimpleSchedule(x => x.WithIntervalInSeconds(1).RepeatForever())) 59 | .UseQuartzJob(() => 60 | { 61 | return TriggerBuilder.Create() 62 | .WithSimpleSchedule(x => x.WithIntervalInSeconds(1).RepeatForever()); 63 | }); 64 | } 65 | if (settings.Value.EnableHelloJob) 66 | { 67 | app.UseQuartzJob(new List 68 | { 69 | TriggerBuilder.Create() 70 | .WithSimpleSchedule(x => x.WithIntervalInSeconds(1).RepeatForever()), 71 | TriggerBuilder.Create() 72 | .WithSimpleSchedule(x => x.WithIntervalInSeconds(2).RepeatForever()) 73 | }); 74 | 75 | app.UseQuartzJob(() => 76 | { 77 | var result = new List(); 78 | result.Add(TriggerBuilder.Create() 79 | .WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever())); 80 | return result; 81 | }); 82 | 83 | } 84 | } 85 | 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /test/QuartzHostedService.Test/QuartzHostedServiceUnitTest.cs: -------------------------------------------------------------------------------- 1 | using FakeItEasy; 2 | using Quartz; 3 | using Quartz.Spi; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using Xunit; 10 | 11 | namespace QuartzHostedService.Test 12 | { 13 | public class QuartzHostedServiceUnitTest 14 | { 15 | [Fact(DisplayName = "Устанавливаем JobFactory (Для DI)")] 16 | public async void IServiceCollectionExtensions_Register_HostedService() 17 | { 18 | IServiceProvider serviceProvider = A.Fake(); 19 | A.CallTo(() => serviceProvider.GetService(typeof(IEnumerable))).Returns(null); 20 | 21 | ISchedulerFactory schedulerFactory = A.Fake(); 22 | IScheduler scheduler = A.Fake(); 23 | A.CallTo(() => schedulerFactory.GetScheduler(A.Ignored)) 24 | .Returns(Task.FromResult(scheduler)); 25 | 26 | IJobFactory jobFactory = A.Fake(); 27 | 28 | var testClass = new QuartzHostedService(serviceProvider, schedulerFactory, jobFactory); 29 | await testClass.StartAsync(CancellationToken.None); 30 | 31 | A.CallTo(scheduler) 32 | .Where(a => a.Method.Name.Equals("set_JobFactory")); 33 | } 34 | 35 | 36 | [Fact(DisplayName = "Запустили все зарегистрированые Job")] 37 | public async void IServiceCollectionExtensions_Register_RegisterJob() 38 | { 39 | // Зарегистрированные джобы 40 | var scheduleJobc = new List(); 41 | var jobDetail1 = A.Fake(); 42 | var jobDetail2 = A.Fake(); 43 | var jobDetail3 = A.Fake(); 44 | 45 | scheduleJobc.Add(new ScheduleJob(jobDetail1, new List() { A.Fake() })); 46 | scheduleJobc.Add(new ScheduleJob(jobDetail2, new List() { A.Fake() })); 47 | scheduleJobc.Add(new ScheduleJob(jobDetail3, new List() { A.Fake() })); 48 | 49 | IServiceProvider serviceProvider = A.Fake(); 50 | A.CallTo(() => serviceProvider.GetService(typeof(IEnumerable))).Returns(scheduleJobc); 51 | 52 | 53 | ISchedulerFactory schedulerFactory = A.Fake(); 54 | IScheduler scheduler = A.Fake(); 55 | A.CallTo(() => schedulerFactory.GetScheduler(A.Ignored)) 56 | .Returns(Task.FromResult(scheduler)); 57 | 58 | IJobFactory jobFactory = A.Fake(); 59 | 60 | var testClass = new QuartzHostedService(serviceProvider, schedulerFactory, jobFactory); 61 | await testClass.StartAsync(CancellationToken.None); 62 | 63 | A.CallTo( 64 | () => scheduler.ScheduleJob( 65 | A.That.Matches(jd => jd == jobDetail1 || jd == jobDetail2 || jd == jobDetail3), 66 | A.Ignored, 67 | A.Ignored)) 68 | .MustHaveHappened(Repeated.Like(count => count == 3)); 69 | } 70 | 71 | [Fact(DisplayName = "Запустили все зарегистрированые Job с указанными ITrigger")] 72 | public async void IServiceCollectionExtensions_Register_RegisterJob_ITrigger() 73 | { 74 | // Зарегистрированные джобы 75 | var scheduleJobc = new List(); 76 | var jobDetail1 = A.Fake(); 77 | 78 | var trigger1 = A.Fake(); 79 | var trigger2 = A.Fake(); 80 | var trigger3 = A.Fake(); 81 | scheduleJobc.Add(new ScheduleJob(jobDetail1, new List() { trigger1, trigger2, trigger3 })); 82 | 83 | IServiceProvider serviceProvider = A.Fake(); 84 | A.CallTo(() => serviceProvider.GetService(typeof(IEnumerable))).Returns(scheduleJobc); 85 | 86 | 87 | ISchedulerFactory schedulerFactory = A.Fake(); 88 | IScheduler scheduler = A.Fake(); 89 | A.CallTo(() => schedulerFactory.GetScheduler(A.Ignored)) 90 | .Returns(Task.FromResult(scheduler)); 91 | 92 | IJobFactory jobFactory = A.Fake(); 93 | 94 | var testClass = new QuartzHostedService(serviceProvider, schedulerFactory, jobFactory); 95 | await testClass.StartAsync(CancellationToken.None); 96 | 97 | A.CallTo( 98 | () => scheduler.ScheduleJob( 99 | A.That.Matches(jd => jd == jobDetail1), 100 | A.That.Matches(t => t == trigger1), 101 | A.Ignored)) 102 | .MustHaveHappened(Repeated.Exactly.Once); 103 | 104 | A.CallTo( 105 | () => scheduler.ScheduleJob( 106 | A.That.Matches(t => t == trigger2 || t == trigger3), 107 | A.Ignored)) 108 | .MustHaveHappened(Repeated.Exactly.Twice); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | # publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /QuartzHostedService.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.26124.0 4 | MinimumVisualStudioVersion = 15.0.26124.0 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DD437750-ADAF-4565-9B50-959A92A67100}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuartzHostedService", "src\QuartzHostedService\QuartzHostedService.csproj", "{08939639-5650-4141-9CC7-9B2956701488}" 8 | EndProject 9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{EDF98575-67B2-4C80-87FC-051AAF2A9E8A}" 10 | EndProject 11 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuartzHostedService.Test", "test\QuartzHostedService.Test\QuartzHostedService.Test.csproj", "{B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}" 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{B2530695-ADDC-4F87-9B86-E5AEA6FF8EEC}" 14 | EndProject 15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8D255B81-7BCE-4918-9A49-7DBD91FCBCAA}" 16 | ProjectSection(SolutionItems) = preProject 17 | .gitattributes = .gitattributes 18 | .gitignore = .gitignore 19 | .travis.yml = .travis.yml 20 | README.md = README.md 21 | EndProjectSection 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleQuartzHostedService", "sample\SampleQuartzHostedService\SampleQuartzHostedService.csproj", "{DE3C9BAF-B262-4346-996C-283E974C0449}" 24 | EndProject 25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCoreSampleQuartzHostedService", "sample\AspNetCoreSampleQuartzHostedService\AspNetCoreSampleQuartzHostedService.csproj", "{789628F4-3B6C-4A05-B8A1-B968ED2AF417}" 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|Any CPU = Debug|Any CPU 30 | Debug|x64 = Debug|x64 31 | Debug|x86 = Debug|x86 32 | Release|Any CPU = Release|Any CPU 33 | Release|x64 = Release|x64 34 | Release|x86 = Release|x86 35 | EndGlobalSection 36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 37 | {08939639-5650-4141-9CC7-9B2956701488}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {08939639-5650-4141-9CC7-9B2956701488}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {08939639-5650-4141-9CC7-9B2956701488}.Debug|x64.ActiveCfg = Debug|Any CPU 40 | {08939639-5650-4141-9CC7-9B2956701488}.Debug|x64.Build.0 = Debug|Any CPU 41 | {08939639-5650-4141-9CC7-9B2956701488}.Debug|x86.ActiveCfg = Debug|Any CPU 42 | {08939639-5650-4141-9CC7-9B2956701488}.Debug|x86.Build.0 = Debug|Any CPU 43 | {08939639-5650-4141-9CC7-9B2956701488}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {08939639-5650-4141-9CC7-9B2956701488}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {08939639-5650-4141-9CC7-9B2956701488}.Release|x64.ActiveCfg = Release|Any CPU 46 | {08939639-5650-4141-9CC7-9B2956701488}.Release|x64.Build.0 = Release|Any CPU 47 | {08939639-5650-4141-9CC7-9B2956701488}.Release|x86.ActiveCfg = Release|Any CPU 48 | {08939639-5650-4141-9CC7-9B2956701488}.Release|x86.Build.0 = Release|Any CPU 49 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Debug|x64.ActiveCfg = Debug|Any CPU 52 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Debug|x64.Build.0 = Debug|Any CPU 53 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Debug|x86.ActiveCfg = Debug|Any CPU 54 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Debug|x86.Build.0 = Debug|Any CPU 55 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Release|Any CPU.ActiveCfg = Release|Any CPU 56 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Release|Any CPU.Build.0 = Release|Any CPU 57 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Release|x64.ActiveCfg = Release|Any CPU 58 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Release|x64.Build.0 = Release|Any CPU 59 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Release|x86.ActiveCfg = Release|Any CPU 60 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2}.Release|x86.Build.0 = Release|Any CPU 61 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 62 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Debug|Any CPU.Build.0 = Debug|Any CPU 63 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Debug|x64.ActiveCfg = Debug|Any CPU 64 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Debug|x64.Build.0 = Debug|Any CPU 65 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Debug|x86.ActiveCfg = Debug|Any CPU 66 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Debug|x86.Build.0 = Debug|Any CPU 67 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Release|Any CPU.ActiveCfg = Release|Any CPU 68 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Release|Any CPU.Build.0 = Release|Any CPU 69 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Release|x64.ActiveCfg = Release|Any CPU 70 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Release|x64.Build.0 = Release|Any CPU 71 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Release|x86.ActiveCfg = Release|Any CPU 72 | {DE3C9BAF-B262-4346-996C-283E974C0449}.Release|x86.Build.0 = Release|Any CPU 73 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 74 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Debug|Any CPU.Build.0 = Debug|Any CPU 75 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Debug|x64.ActiveCfg = Debug|Any CPU 76 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Debug|x64.Build.0 = Debug|Any CPU 77 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Debug|x86.ActiveCfg = Debug|Any CPU 78 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Debug|x86.Build.0 = Debug|Any CPU 79 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Release|Any CPU.ActiveCfg = Release|Any CPU 80 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Release|Any CPU.Build.0 = Release|Any CPU 81 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Release|x64.ActiveCfg = Release|Any CPU 82 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Release|x64.Build.0 = Release|Any CPU 83 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Release|x86.ActiveCfg = Release|Any CPU 84 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417}.Release|x86.Build.0 = Release|Any CPU 85 | EndGlobalSection 86 | GlobalSection(SolutionProperties) = preSolution 87 | HideSolutionNode = FALSE 88 | EndGlobalSection 89 | GlobalSection(NestedProjects) = preSolution 90 | {08939639-5650-4141-9CC7-9B2956701488} = {DD437750-ADAF-4565-9B50-959A92A67100} 91 | {B6BE5ED4-B7F3-48C3-8374-8B479F40F5F2} = {EDF98575-67B2-4C80-87FC-051AAF2A9E8A} 92 | {DE3C9BAF-B262-4346-996C-283E974C0449} = {B2530695-ADDC-4F87-9B86-E5AEA6FF8EEC} 93 | {789628F4-3B6C-4A05-B8A1-B968ED2AF417} = {B2530695-ADDC-4F87-9B86-E5AEA6FF8EEC} 94 | EndGlobalSection 95 | GlobalSection(ExtensibilityGlobals) = postSolution 96 | SolutionGuid = {C92A5047-9DD9-4F11-9FEE-F1AB1679F94F} 97 | EndGlobalSection 98 | EndGlobal 99 | -------------------------------------------------------------------------------- /src/QuartzHostedService/IJobRegistratorExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Quartz; 4 | using Quartz.Spi; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace QuartzHostedService 13 | { 14 | public static class IJobRegistratorExtensions 15 | { 16 | public static IJobRegistrator RegiserCRONJob( 17 | this IJobRegistrator jobRegistrator, 18 | Action jobOptions) 19 | where TJob : class, IJob 20 | { 21 | var options = new JobOptions(); 22 | jobOptions?.Invoke(options); 23 | 24 | return jobRegistrator.RegiserJob( 25 | options.Triggers?.Select(n => n.CreateTriggerBuilder()) 26 | ); 27 | } 28 | 29 | 30 | public static IJobRegistrator RegiserJob( 31 | this IJobRegistrator jobRegistrator, 32 | Func> triggers) 33 | where TJob : class, IJob 34 | { 35 | 36 | return jobRegistrator.RegiserJob(triggers()); 37 | } 38 | public static IServiceCollection AddQuartzJobDetail(this IServiceCollection services, Func detail) 39 | { 40 | services.AddSingleton(provider => new ScheduleJob(detail(), new List())); 41 | return services; 42 | } 43 | public static IServiceCollection AddQuartzJob(this IServiceCollection services, string identity) where TJob : class 44 | { 45 | return services.AddQuartzJob(identity, null); 46 | } 47 | 48 | public static IServiceCollection AddQuartzJob(this IServiceCollection services, string identity, string description) where TJob : class 49 | { 50 | if (!services.Any(sd => sd.ServiceType == typeof(TJob))) 51 | { 52 | services.AddTransient(); 53 | } 54 | var jobDetail = JobBuilder.Create(typeof(TJob)).WithIdentity(identity).WithDescription(description).Build(); 55 | services.AddSingleton(provider => new ScheduleJob(jobDetail, new List())); 56 | return services; 57 | } 58 | 59 | 60 | public static IServiceCollection AddQuartzJobDetail(this IServiceCollection services, IJobDetail detail) 61 | { 62 | services.AddSingleton(provider => new ScheduleJob(detail, new List())); 63 | return services; 64 | } 65 | public static IServiceCollection AddQuartzJob(this IServiceCollection services) where TJob : class 66 | { 67 | services.AddTransient(); 68 | var jobDetail = JobBuilder.Create(typeof(TJob)).Build(); 69 | services.AddSingleton(provider => new ScheduleJob(jobDetail, new List())); 70 | return services; 71 | } 72 | public static IApplicationBuilder UseQuartzJob( 73 | this IApplicationBuilder app, 74 | Func triggerBuilder_func) 75 | where TJob : class, IJob 76 | { 77 | return app.UseQuartzJob(new TriggerBuilder[] { triggerBuilder_func() }); 78 | } 79 | public static IApplicationBuilder UseQuartzJob( 80 | this IApplicationBuilder app,string JobKey, 81 | Func triggerBuilder_func) 82 | where TJob : class, IJob 83 | { 84 | var _scheduleJobs = app.ApplicationServices.GetService>(); 85 | var job = from js in _scheduleJobs where js.JobDetail.JobType == typeof(TJob) && js.JobDetail.Key.Name == JobKey select js; 86 | if (job.Any()) 87 | { 88 | var scheduleJob = job.First(); 89 | var lstgs = (List)scheduleJob.Triggers; 90 | lstgs.Add(triggerBuilder_func().ForJob(scheduleJob.JobDetail).Build()); 91 | } 92 | return app; 93 | } 94 | 95 | public static IApplicationBuilder UseQuartzJob( 96 | this IApplicationBuilder app, 97 | TriggerBuilder triggerBuilder) 98 | where TJob : class, IJob 99 | { 100 | return app.UseQuartzJob(new TriggerBuilder[] { triggerBuilder }); 101 | } 102 | 103 | public static IApplicationBuilder UseQuartzJob( 104 | this IApplicationBuilder app, 105 | Func> triggerBuilders_func) 106 | where TJob : class, IJob 107 | { 108 | return app.UseQuartzJob(triggerBuilders_func()); 109 | } 110 | public static IApplicationBuilder UseQuartzJob( 111 | this IApplicationBuilder app, 112 | IEnumerable triggerBuilders) 113 | where TJob : class, IJob 114 | { 115 | var _scheduleJobs = app.ApplicationServices.GetService>(); 116 | var job = from js in _scheduleJobs where js.JobDetail.JobType == typeof(TJob) select js; 117 | if (job.Any()) 118 | { 119 | var scheduleJob = job.First(); 120 | var lstgs = (List)scheduleJob.Triggers; 121 | foreach (var triggerBuilder in triggerBuilders) 122 | { 123 | lstgs.Add(triggerBuilder.ForJob(scheduleJob.JobDetail).Build()); 124 | } 125 | } 126 | return app; 127 | } 128 | public static IJobRegistrator RegiserJob( 129 | this IJobRegistrator jobRegistrator, 130 | IEnumerable triggerBuilders) 131 | where TJob : class, IJob 132 | { 133 | jobRegistrator.Services.AddTransient(); 134 | 135 | var jobDetail = JobBuilder.Create().Build(); 136 | 137 | List triggers = new List(triggerBuilders.Count()); 138 | foreach (var triggerBuilder in triggerBuilders) 139 | { 140 | triggers.Add(triggerBuilder.ForJob(jobDetail).Build()); 141 | } 142 | 143 | jobRegistrator.Services.AddSingleton(provider => new ScheduleJob(jobDetail, triggers)); 144 | 145 | return jobRegistrator; 146 | } 147 | } 148 | } 149 | --------------------------------------------------------------------------------