Как стать автором
Обновить

Комментарии 7

Я ользовался такой реализацией, но суть таже
Spoiler header
public class MicrosoftDependencyInjectionJobFactory : IJobFactory
	{
		private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
		private readonly IServiceProvider _container;

		/// <summary>
		/// 	.ctor
		/// </summary>
		/// <param name="container"></param>
		public MicrosoftDependencyInjectionJobFactory(IServiceProvider container)
		{
			_container = container;
		}

		/// <inheritdoc />
		public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
		{
			// Отлавливаем ошибки получения сервиса из DI 
			try
			{
				var job = _container.GetService(bundle.JobDetail.JobType) as IJob;
				if (job != null)
				{
					return job;
				}
				else
				{
					var exception = new Exception($"Can't cast {bundle.JobDetail.JobType} to {typeof(IJob)}");
					Logger.Error(exception);
					throw exception;
				}
			}
			catch (Exception exception)
			{
				Logger.Error(exception, $"Can't get {bundle.JobDetail.JobType} through DI");
				throw;
			}
		}

		/// <inheritdoc />
		public void ReturnJob(IJob job)
		{
			var disposable = job as IDisposable;
			disposable?.Dispose();
		}
	}

Да, спасибо, видел что-то подобное!

Вы неправильно используете IServiceScope — вы его уничтожаете сразу после создания, не дождавшись выполнения задачи. А используя ActivatorUtilities из Microsoft.Extensions.DependencyInjection можно избежать регистрации самих задач в контейнере.
Код
public class JobFactory : IJobFactory
{
    private readonly IServiceProvider _provider;

    public JobFactory(IServiceProvider provider)
    {
        _provider = provider;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        return new JobWrapper(_provider, bundle.JobDetail.JobType);
    }

    public void ReturnJob(IJob job)
    {
        (job as IDisposable)?.Dispose();
    }
}

public class JobWrapper : IJob, IDisposable
{
    private readonly IServiceScope _serviceScope;
    private readonly IJob _job;

    public JobWrapper(IServiceProvider serviceProvider, Type jobType)
    {
        _serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
        _job = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, jobType) as IJob;
    }

    public Task Execute(IJobExecutionContext context)
    {
        return _job.Execute(context);
    }

    public void Dispose()
    {
        _serviceScope.Dispose();
    }
}

public class DataJob : IJob
{
    private readonly IEmailSender _emailSender;

    public DataJob(IEmailSender emailSender)
    {
        _emailSender = emailSender;
    }

    public async Task Execute(IJobExecutionContext context)
    {
        await _emailsender.SendEmailAsync("example@gmail.com", "example", "hello");
    }
}

Хотите сказать, что может неправильно выполняться (просто у меня никаких проблем не возникало и выполнялись задачи даже после удаления IServiceScope)
Это потому что вы не используете IDisposable ресурсов, которые кидают ObjectDisposedException (например: HttpClient).
Нет ли ничего плохого в том что у вас host.Run() запускается после уничтожения scope?
На часом деле, комментатор выше тоже указал на это, но я не видел чтобы это влияло на работу, так-как, полагаю, задачи уже «забиты» в планировщик и выполнялись с указанным интервалом.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации