ASP Core 2.1 Dependency Injection to Quartz - c#

I am trying to inject services into my SendEmailJob class.
I use standard ASP Core dependency injection and Quartz library for scheduling.
I am trying to build solution based on this answer. But still I am facing injecting issues.
I have such code setup:
//Startup.cs, ConfigureServices
ServiceAutoConfig.Configure(allServices);
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddTransient<IJobFactory, JobFactory>((provider) => new JobFactory(services.BuildServiceProvider()));
services.AddTransient<SendEmailJob>();
//Startup.cs, Configure
app.UseQuartz((quartz) => quartz.AddJob<SendEmailJob>("SendEmailJob", "Email", mailSettings.EmailSchedulerInterval));
Implementation of SendEmailJob:
public class SendEmailJob : IJob
{
private readonly IMessageService _messageService;
private static bool IsBusy = false;
public SendEmailJob(IMessageService messageService)
{
_messageService = messageService;
}
public async Task Execute(IJobExecutionContext context)
{
try
{
if (IsBusy)
return;
IsBusy = true;
//...
}
catch (Exception error)
{
}
finally
{
IsBusy = false;
}
}
}
Implementation of JobFacctory:
public class JobFactory : IJobFactory
{
protected readonly IServiceProvider _container;
public JobFactory(IServiceProvider container)
{
_container = container;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
var res = _container.GetService(bundle.JobDetail.JobType) as IJob;
return res;
}
catch (Exception ex)
{
//ERROR- Cannot resolve 'Quartz.Jobs.SendEmailJob' from root provider because it
// requires scoped service 'BLL.Base.UnitOfWork.Interfaces.IUnitOfWork'.
throw;
}
}
public void ReturnJob(IJob job)
{
(job as IDisposable)?.Dispose();
}
}
Implementation of Quartz.cs
public class Quartz
{
private IScheduler _scheduler;
public static IScheduler Scheduler { get { return Instance._scheduler; } }
private static Quartz _instance = null;
public static Quartz Instance
{
get
{
if (_instance == null)
{
_instance = new Quartz();
}
return _instance;
}
}
private Quartz()
{
Init();
}
private async void Init()
{
_scheduler = await new StdSchedulerFactory().GetScheduler();
}
public IScheduler UseJobFactory(IJobFactory jobFactory)
{
Scheduler.JobFactory = jobFactory;
return Scheduler;
}
public async void AddJob<T>(string name, string group, int interval)
where T : IJob
{
IJobDetail job = JobBuilder.Create<T>()
.WithIdentity(name, group)
.Build();
ITrigger jobTrigger = TriggerBuilder.Create()
.WithIdentity(name + "Trigger", group)
.StartNow()
.WithSimpleSchedule(t => t.WithIntervalInSeconds(interval).RepeatForever()) // Mit wiederholung alle interval sekunden
.Build();
await Scheduler.ScheduleJob(job, jobTrigger);
}
public static async void Start()
{
await Scheduler.Start();
}
}
And implementation of UseQuartzExtension:
public static void UseQuartz(this IApplicationBuilder app, Action<Quartz> configuration)
{
var jobFactory = new JobFactory(app.ApplicationServices);
Quartz.Instance.UseJobFactory(jobFactory);
configuration.Invoke(Quartz.Instance);
Quartz.Start();
}
And there is an error while injecting IMessageService into SendMailJob.
Because it requires UnitOfWork or fails on any other scoped service.
Could you please explain me how to inject it correct?

The problem is that you register IUnitOfWork as scoped, but you don't have any scope at the moment when you resolve it. Create it before resolving your job:
public class JobFactory : IJobFactory, IDisposable
{
protected readonly IServiceScope _scope;
public JobFactory(IServiceProvider container)
{
_scope = container.CreateScope();
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
var res = _scope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob;
return res;
}
public void ReturnJob(IJob job)
{
(job as IDisposable)?.Dispose();
}
public void Dispose()
{
_scope.Dispose();
}
}

I'm not sure if you were able to resolve the disposed DbContext issue you mentioned in your comment, but I'm working on a to be released .NET core app with the same problem and came up with a solution similar to Alex Riabov but uses a concurrent dictionary to dispose the scope when the job has ended. The result is a new dbcontext is injected into my job when a new job is instantiated.
public class QuartzJobFactory : IJobFactory
{
protected readonly IServiceProvider serviceProvider;
private ConcurrentDictionary<IJob, IServiceScope> scopes = new ConcurrentDictionary<IJob, IServiceScope>();
public QuartzJobFactory(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
// instantiation of new job
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try {
var scope = serviceProvider.CreateScope();
var job = scope.ServiceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
scopes.TryAdd(job, scope);
return job;
}
catch (Exception ex) {
throw;
}
}
// executes when job is complete
public void ReturnJob(IJob job)
{
try {
(job as IDisposable)?.Dispose();
if (scopes.TryRemove(job, out IServiceScope scope))
scope.Dispose();
}
catch (Exception ex) {
}
}
}

Related

.NET Core Console App | Hangfire With Dependency Injection

Goal:
Fundamentally I am trying to add a background job, that has dependencies injected, to a console application.
Problem:
Although the jobs are queued, they are never executed.
Program.cs
var appSettings = ConfigHelper.GetConfig();
Console.WriteLine("Initialising Hangfire Server...");
GlobalConfiguration.Configuration.UseSqlServerStorage(appSettings.ConnectionString);
using (var server = new BackgroundJobServer())
{
Console.WriteLine("Hangfire Server started.");
var t = serviceProvider.GetService<ITestService>();
t.Test();
Console.ReadKey();
}
ServiceProviderFactory.cs
public static void Setup()
{
IServiceCollection services = new ServiceCollection();
...
services.AddDbContext<Db>(x => x.UseSqlServer(appSettings.ConnectionString));
services.AddTransient<IInsertLogJob, InsertLogJob>();
services.AddTransient<ITestService, TestService>();
_serviceProvider = services.BuildServiceProvider();
}
TestService.cs
public interface ITestService
{
void Test();
}
public class TestService : ITestService
{
private readonly ILogger<TestService> _logger;
public TestService(ILogger<TestService> logger)
{
_logger = logger;
}
public void Test()
{
logger.LogInformation("Test");
_logger.LogError("Error");
}
}
Logger.cs
public class Logger : ILogger
{
...
Log log = new Log()
{
Message = message,
EventId = eventId.Id,
ObjectId = eventId.Name,
LogLevel = logLevel.ToString(),
CreatedTime = DateTime.Now
};
BackgroundJob.Enqueue<IInsertLogJob>(j => j.Insert(log));
}
InsertLogJob.cs
public interface IInsertLogJob
{
void Insert(Log log);
}
public class InsertLogJob : IInsertLogJob
{
private Db _dataContext;
public InsertLogJob(Db context)
{
_dataContext = context;
}
public void Insert(Log log)//<-- this never happens
{
_dataContext.Logs.Add(log);
_dataContext.SaveChanges();
}
}
DB Record
So all the code up to the point where the data has to be inserted into the database runs, the Hangfire job gets inserted as per the picture above, but the code is never executed.

asp.NET Core timed BackgroundService cannot be stopped in Controller with StopAsync()

I have implemented a REST API Server with asp.NET Core. I need a background task which does some administrative stuff.
I tried the several suggestions in the web to create a timed background task and implemented it as fpllowing:
BackgroundService.cs
public abstract class BackgroundService : IHostedService, IDisposable
{
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
public virtual Task StartAsync(CancellationToken cancellationToken)
{
_executingTask = ExecuteAsync(_stoppingCts.Token);
if (_executingTask.IsCompleted)
{
return _executingTask;
}
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
if (_executingTask == null)
{
return;
}
try
{
_stoppingCts.Cancel();
}
finally
{
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}
RecureHostedService.cs
public class RecureHostedService : BackgroundService
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private int _executionCount = 0;
private Timer _timer;
protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var count = Interlocked.Increment(ref _executionCount);
log.InfoFormat(
"Timed Hosted Service is working. Count: {0}", count);
await Task.Delay(10000, stoppingToken);
}
}
}
SystemController.cs
public class SystemController : Controller
{
private readonly RecureHostedService _recureHostedService;
public SystemController(IHostedService hostedService)
{
_recureHostedService = hostedService as RecureHostedService;
}
[HttpGet(ApiRoutes.System.Start)]
public IActionResult Start()
{
Console.WriteLine("Start Service");
_recureHostedService.StartAsync(new CancellationToken());
return Ok();
}
[HttpGet(ApiRoutes.System.Stop)]
public IActionResult Stop()
{
Console.WriteLine("Stop Service");
Console.WriteLine(_recureHostedService == null);
_recureHostedService.StopAsync(new CancellationToken());
return Ok();
}
}
in Startup.cs I added the Service as Singleton:
services.AddSingleton<IHostedService,RecureHostedService>();
The RecureHostedService starts on startup of my app and does its work. When I do an APIrequest /api/v1/stop from the SystemController (method Stop()) I got an NullReferenceException in
_recureHostedService.StopAsync(new CancellationToken());
I found out that the private member variable _recureHostedService is null even if I had assigned it in the Constructor of the SystemController. So it seems that the Service Injection of _recureHostedService is not working. So the line
_recureHostedService = hostedService as RecureHostedService;
in the Constructor of SystemController assigns null to _recureHostedService.
How can that be? I've a lot of other Services injected to other Controllers and all works fine.
Any idea from anyone, why it is not working with that Hosted Service?
Best
Mic
I used a set of static variables for myself
public class RecureHostedService : BackgroundService {
public static bool isPause = false;
/* for example
public static string ErrorText;
public static bool isError = false;
public static bool isWorked = false;
public static bool firstStart = true; */
protected async override Task ExecuteAsync(CancellationToken stoppingToken){
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
if (isPause)
continue;
var count = Interlocked.Increment(ref _executionCount);
log.InfoFormat(
"Timed Hosted Service is working. Count: {0}", count);
await Task.Delay(10000, stoppingToken);
}
}
}
public class SystemController : Controller
{
[HttpGet(ApiRoutes.System.Start)]
public IActionResult Start()
{
Console.WriteLine("Start Service");
RecureHostedService.isPause = false;
return Ok();
}
[HttpGet(ApiRoutes.System.Stop)]
public IActionResult Stop()
{
Console.WriteLine("Stop Service");
RecureHostedService.isPause = true;
return Ok();
}
}
You need to register you hosted service using AddHostedService instedad of AddSingleton
so it will be something like this
services.AddHostedService<IHostedService,RecureHostedService>();
If you perfer inject IHostedService on constructor, keep _recureHostedService property declared as type of IHostedService, instead of the concrete class RecureHostedService. It's not necessary down-casting here.
[Route("[controller]")]
public class SystemController : Controller
{
private readonly IHostedService _recureHostedService;
public SystemController(IHostedService hostedService)
{
_recureHostedService = hostedService ?? throw new ArgumentNullException(nameof(hostedService));
}
}
Update
I've tested this controller, no null exception any longer in either this way
services.AddSingleton<IHostedService, RecureHostedService>();
or
services.AddHostedService(p =>
{
return new RecureHostedService();
});
Using dependency injection to obtain an IHostedService will inject whichever hosted service was defined first. Which is likely to be the web server itself. Instead you should define two service definitions that return the same singleton;
services.AddSingleton<RecureHostedService>();
services.AddSingleton<IHostedService>(p => p.GetRequiredService<RecureHostedService>());
public class SystemController : Controller
{
private readonly RecureHostedService _recureHostedService;
public SystemController(RecureHostedService hostedService)
{
_recureHostedService = hostedService;
}
}

Property injection

I'm trying make a telegram bot with reminder. I'm using Telegram.Bot 14.10.0, Quartz 3.0.7, .net core 2.0. The first version should : get message "reminder" from telegram, create job (using Quartz) and send meaasage back in 5 seconds.
My console app with DI looks like:
Program.cs
static IBot _botClient;
public static void Main(string[] args)
{
// it doesn't matter
var servicesProvider = BuildDi(connecionString, section);
_botClient = servicesProvider.GetRequiredService<IBot>();
_botClient.Start(appModel.BotConfiguration.BotToken, httpProxy);
var reminderJob = servicesProvider.GetRequiredService<IReminderJob>();
reminderJob.Bot = _botClient;
Console.ReadLine();
_botClient.Stop();
// it doesn't matter
}
private static ServiceProvider BuildDi(string connectionString, IConfigurationSection section)
{
var rJob = new ReminderJob();
var sCollection = new ServiceCollection()
.AddSingleton<IBot, Bot>()
.AddSingleton<ReminderJob>(rJob)
.AddSingleton<ISchedulerBot>(s =>
{
var schedBor = new SchedulerBot();
schedBor.StartScheduler();
return schedBor;
});
return sCollection.BuildServiceProvider();
}
Bot.cs
public class Bot : IBot
{
static TelegramBotClient _botClient;
public void Start(string botToken, WebProxy httpProxy)
{
_botClient = new TelegramBotClient(botToken, httpProxy);
_botClient.OnReceiveError += BotOnReceiveError;
_botClient.OnMessage += Bot_OnMessage;
_botClient.StartReceiving();
}
private static async void Bot_OnMessage(object sender, MessageEventArgs e)
{
var me = wait _botClient.GetMeAsync();
if (e.Message.Text == "reminder")
{
var map= new Dictionary<string, object> { { ReminderJobConst.ChatId, e.Message.Chat.Id.ToString() }, { ReminderJobConst.HomeWordId, 1} };
var job = JobBuilder.Create<ReminderJob>().WithIdentity($"{prefix}{rnd.Next()}").UsingJobData(new JobDataMap(map)).Build();
var trigger = TriggerBuilder.Create().WithIdentity($"{prefix}{rnd.Next()}").StartAt(DateTime.Now.AddSeconds(5).ToUniversalTime())
.Build();
await bot.Scheduler.ScheduleJob(job, trigger);
}
}
}
Quartz.net not allow use constructor with DI. That's why I'm trying to create property with DI.
ReminderJob.cs
public class ReminderJob : IJob
{
static IBot _bot;
public IBot Bot { get; set; }
public async Task Execute(IJobExecutionContext context)
{
var parameters = context.JobDetail.JobDataMap;
var userId = parameters.GetLongValue(ReminderJobConst.ChatId);
var homeWorkId = parameters.GetLongValue(ReminderJobConst.HomeWordId);
await System.Console.Out.WriteLineAsync("HelloJob is executing.");
}
}
How can I pass _botClient to reminderJob in Program.cs?
If somebody looks for answer, I have one:
Program.cs (in Main)
var schedBor = servicesProvider.GetRequiredService<ISchedulerBot>();
var logger = servicesProvider.GetRequiredService<ILogger<DIJobFactory>>();
schedBor.StartScheduler();
schedBor.Scheduler.JobFactory = new DIJobFactory(logger, servicesProvider);
DIJobFactory.cs
public class DIJobFactory : IJobFactory
{
static ILogger<DIJobFactory> _logger;
static IServiceProvider _serviceProvider;
public DIJobFactory(ILogger<DIJobFactory> logger, IServiceProvider sp)
{
_logger = logger;
_serviceProvider = sp;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
IJobDetail jobDetail = bundle.JobDetail;
Type jobType = jobDetail.JobType;
try
{
_logger.LogDebug($"Producing instance of Job '{jobDetail.Key}', class={jobType.FullName}");
if (jobType == null)
{
throw new ArgumentNullException(nameof(jobType), "Cannot instantiate null");
}
return (IJob)_serviceProvider.GetRequiredService(jobType);
}
catch (Exception e)
{
SchedulerException se = new SchedulerException($"Problem instantiating class '{jobDetail.JobType.FullName}'", e);
throw se;
}
}
// get from https://github.com/quartznet/quartznet/blob/139aafa23728892b0a5ebf845ce28c3bfdb0bfe8/src/Quartz/Simpl/SimpleJobFactory.cs
public void ReturnJob(IJob job)
{
var disposable = job as IDisposable;
disposable?.Dispose();
}
}
ReminderJob.cs
public interface IReminderJob : IJob
{
}
public class ReminderJob : IReminderJob
{
ILogger<ReminderJob> _logger;
IBot _bot;
public ReminderJob(ILogger<ReminderJob> logger, IBot bot)
{
_logger = logger;
_bot = bot;
}
public async Task Execute(IJobExecutionContext context)
{
var parameters = context.JobDetail.JobDataMap;
var userId = parameters.GetLongValue(ReminderJobConst.ChatId);
var homeWorkId = parameters.GetLongValue(ReminderJobConst.HomeWordId);
await _bot.Send(userId.ToString(), "test");
}
}

NInject and Quartz.net problems

I have been reading a lot for DI and Quartz.net using ninject and I can't make it run. I'm trying to follow this link. This is my code:
This is the job:
public class ClientsImportJob : IJob
{
private readonly IUserClientImportService _userClientImportService;
public ClientsImportJob(IUserClientImportService userClientImportService)
{
_userClientImportService = userClientImportService;
}
public void Execute(IJobExecutionContext context)
{
_userClientImportService.ProcessFiles();
}
}
This is the Factory:
public class NInjectJobFactory : SimpleJobFactory
{
readonly IKernel _kernel;
public NInjectJobFactory(IKernel kernel)
{
this._kernel = kernel;
}
public override IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
return (IJob) this._kernel.Get(bundle.JobDetail.JobType); // will inject dependencies that the job requires
}
catch (Exception e)
{
throw new SchedulerException(string.Format("Problem while instantiating job '{0}' from the NinjectJobFactory.", bundle.JobDetail.Key), e);
}
}
}
And this is where I call the scheduller:
public class QuartzService
{
public static void ScheduleImportTask()
{
var kernel = InitializeNinjectKernel();
var scheduler = kernel.Get<IScheduler>();
scheduler.ScheduleJob(
JobBuilder.Create<ClientsImportJob>().Build(),
TriggerBuilder.Create().WithSimpleSchedule(s => s.WithIntervalInSeconds(10).RepeatForever()).Build());
scheduler.Start();
}
private static IKernel InitializeNinjectKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IScheduler>().ToMethod(x =>
{
var sched = new StdSchedulerFactory().GetScheduler();
sched.JobFactory = new NInjectJobFactory(kernel);
return sched;
});
kernel.Bind<IUserClientImportService>().To<UserClientImportService>();
return kernel;
}
}
What am I doing wrong?

Constructor injection with Quartz.NET and Simple Injector

Currently I am writing a service using Quartz.NET to schedule the running of it.
I was wondering if anyone has any experience of using constructor injection with Quartz.NET and Simple Injector.
Below is essentially what I wish to achieve
public class JobImplementation: IJob
{
private readonly IInjectedClass injectedClass;
public JobImplementation(IInjectedClass _injectedClass)
{
injectedClass = _injectedClass
}
public void Execute(IJobExecutionContext _context)
{
//Job code
}
According to this blog post, you would need to implement a custom IJobFactory, like this:
public class SimpleInjectorJobFactory : IJobFactory
{
private readonly Container container;
private readonly Dictionary<Type, InstanceProducer> jobProducers;
public SimpleInjectorJobFactory(
Container container, params Assembly[] assemblies)
{
this.container = container;
// By creating producers, jobs can be decorated.
var transient = Lifestyle.Transient;
this.jobProducers =
container.GetTypesToRegister(typeof(IJob), assemblies).ToDictionary(
type => type,
type => transient.CreateProducer(typeof(IJob), type, container));
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler _)
{
var jobProducer = this.jobProducers[bundle.JobDetail.JobType];
return new AsyncScopedJobDecorator(
this.container, () => (IJob)jobProducer.GetInstance());
}
public void ReturnJob(IJob job)
{
// This will be handled automatically by Simple Injector
}
private sealed class AsyncScopedJobDecorator : IJob
{
private readonly Container container;
private readonly Func<IJob> decorateeFactory;
public AsyncScopedJobDecorator(
Container container, Func<IJob> decorateeFactory)
{
this.container = container;
this.decorateeFactory = decorateeFactory;
}
public async Task Execute(IJobExecutionContext context)
{
using (AsyncScopedLifestyle.BeginScope(this.container))
{
var job = this.decorateeFactory();
await job.Execute(context);
}
}
}
}
Furthermore, you'll need the following registrations:
var container = new Container();
container.Options.ScopedLifestyle = new AsyncScopedLifestyle();
var factory = new StdSchedulerFactory();
IScheduler scheduler = await factory.GetScheduler();
scheduler.JobFactory = new SimpleInjectorJobFactory(
container,
Assembly.GetExecutingAssembly()); // assemblies that contain jobs
// Optional: register some decorators
container.RegisterDecorator(typeof(IJob), typeof(LoggingJobDecorator));
container.Verify();
Late to the party, but https://github.com/hbiarge/Quartz.Unity works well for combining Quartz.NET and Unity.
IUnityContainer container = new UnityContainer();
container.AddNewExtension<Quartz.Unity.QuartzUnityExtension>();
// do your other Unity registrations
IScheduler scheduler = container.Resolve<IScheduler>();
scheduler.ScheduleJob(
new JobDetailImpl(myCommandName, typeof(MyCommand)),
TriggerBuilder.Create()
.WithCronSchedule(myCronSchedule)
.StartAt(startTime)
.Build()
);
scheduler.Start();
There are few steps to use Quartz.net with dependency injection engine from asp.net core.
Add nuget package to your project:
Microsoft.Extensions.DependencyInjection
Create custom JobFactory:
public class JobFactory : IJobFactory
{
protected readonly IServiceProvider _serviceProvider;
public JobFactory(IServiceProvider serviceProvider)
=> _serviceProvider = serviceProvider;
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
=> _serviceProvider.GetService(bundle.JobDetail.JobType) as IJob;
public void ReturnJob(IJob job)
=> (job as IDisposable)?.Dispose();
}
Specify JobFactory when configuring scheduler:
var scheduler = await StdSchedulerFactory.GetDefaultScheduler();
scheduler.JobFactory = new JobFactory(_serviceProvider);
For someone can be usefull example of win service with Quartz.net and DI (from asp.net core) on the board:
public class WinService : ServiceBase
{
private Scheduler _scheduleManager;
private readonly Startup _startup;
public WinService()
{
ServiceName = "SomeWinService";
_startup = new Startup();
}
static void Main(string[] args)
{
var service = new WinService();
// Working as Windows-service
if (Console.IsInputRedirected && Console.IsOutputRedirected)
{
ServiceBase.Run(service);
}
// Working as console app
else
{
service.OnStart(args);
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
service.OnStop();
}
}
protected override void OnStart(string[] args)
{
_startup.RegisterServices();
_scheduleManager = new Scheduler(_startup.ServiceProvider);
_scheduleManager.StartTracking().Wait();
}
protected override void OnPause()
=> _scheduleManager.PauseTracking().Wait();
protected override void OnContinue()
=> _scheduleManager.ResumeTracking().Wait();
protected override void OnStop()
{
_scheduleManager.StopTracking().Wait();
_startup.DisposeServices();
}
}
public class Startup
{
private IServiceProvider _serviceProvider;
public IServiceProvider ServiceProvider => _serviceProvider;
public void RegisterServices()
{
_serviceProvider = new ServiceCollection()
//.AddTransient(...)
//.AddScoped(...)
//.AddSingleton(...)
.BuildServiceProvider();
}
public void DisposeServices()
{
if (_serviceProvider == null)
return;
if (_serviceProvider is IDisposable)
{
((IDisposable)_serviceProvider).Dispose();
}
}
}
public class Scheduler
{
private readonly IServiceProvider _serviceProvider;
private IScheduler _scheduler;
public Scheduler(IServiceProvider serviceProvider)
=> _serviceProvider = serviceProvider;
public async Task StartTracking()
{
_scheduler = await StdSchedulerFactory.GetDefaultScheduler();
_scheduler.JobFactory = new JobFactory(_serviceProvider);
await _scheduler.Start();
// Schedule your jobs here
}
public async Task PauseTracking() => await _scheduler?.PauseAll();
public async Task ResumeTracking() => await _scheduler?.ResumeAll();
public async Task StopTracking() => await _scheduler?.Shutdown();
}

Categories

Resources