我正在尝试将服务注入到我的SendEmailJob类中。 我使用标准的ASP Core依赖项注入和Quartz库进行调度。 我正在尝试基于this answer构建解决方案。但是我仍然面临着注入问题。
我有这样的代码设置:
//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));
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;
}
}
}
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();
}
}
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();
}
}
以及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();
}
将IMessageService
注入SendMailJob
时出错。
因为它需要UnitOfWork
或在任何其他范围内的服务上失败。
您能解释一下如何正确注入吗?
答案 0 :(得分:2)
问题是您将IUnitOfWork
注册为作用域,但是在解析它时没有任何作用域。在解决您的工作之前创建它:
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();
}
}
答案 1 :(得分:0)
我不确定您是否能够解决您在评论中提到的DbContext问题,但是我正在开发一个具有相同问题的.NET核心应用程序,并提出了类似于以下内容的解决方案Alex Riabov,但是在作业结束时使用并发字典来处理范围。结果是当实例化新作业时,将新的dbcontext注入到我的作业中。
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) {
}
}
}