#asp.net-core #asp.net-web-api #quartz.net
#asp.net-core #asp.net-web-api #quartz.net
Вопрос:
Я создаю веб-API, используя ASP.NET Ядро и теперь у меня возникла проблема с запланированными заданиями quartz. Задания, которые у меня есть, получат доступ к моим службам для обновления базы данных. После некоторых исследований я понял, как выполнить внедрение зависимостей, чтобы мои задания могли получать доступ к службам, вот как я переопределил фабрику заданий:
public class AspNetCoreJobFactory : SimpleJobFactory
{
IServiceProvider _provider;
public AspNetCoreJobFactory(IServiceProvider provider)
{
_provider = provider;
}
public override IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
return (IJob)this._provider.GetService(bundle.JobDetail.JobType);
}
catch(Exception e)
{
throw new SchedulerException(string.Format("Problem while instantiating job '{0}' from the AspNet Core IOC.", bundle.JobDetail.Key), e);
}
}
}
и я добавил эту строку в свою startup configure:
_quartzScheduler.JobFactory = new AspNetCoreJobFactory(app.ApplicationServices);
Наконец, я добавил эти две строки в свой ConfigureServices
метод:
services.AddSingleton<IUserService, UserService>();
services.AddTransient<BatchJobCheckContract>();
прямо сейчас я получаю это исключение при попытке выполнить задание, похоже, это потому, что моя служба использует DbContext
, как я могу это решить?
Не удается использовать службу с ограниченной областью действия ‘RHP.data.RHPDbContext’ из одноэлементного ‘RHP.data.IServices.Администрирование.IUserService ‘.
Комментарии:
1. Можете ли вы перейти
services.AddSingleton<IUserService, UserService>();
наservices.AddTransient<IUserService, UserService>();
?2. @Shoejep Я только что попробовал это, то же самое исключение
Ответ №1:
После игры с Quartz (версия 3.2.3) похоже, что вам не нужно писать свой собственный JobFactory
, чтобы использовать Microsoft DI. (См . ASP.NET Интеграция с ядром и интеграция с Microsoft DI):
Добавьте Quartz.AspNetCore
пакет nuget, и вы сможете использовать службы, подобные этому:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IScopedService, ScopedService>();
// Job has scoped dependencies, so it must be scoped as well
services.AddScoped<Job>();
services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionScopedJobFactory();
var jobKey = new JobKey("job");
q.AddJob<Job>(jobKey);
q.AddTrigger(t => /* ... */));
});
services.AddQuartzServer(opts => opts.WaitForJobsToComplete = true);
}
Однако, если вы не можете использовать текущую версию Quartz.AspNetCore
, вы все равно
можете использовать IServiceProvider
as dependency в своем Job
классе и разрешать службы там:
public class Job : IJob
{
private readonly IServiceProvider _serviceProvider;
public Job(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public Task Execute(IJobExecutionContext context)
{
using var scope = _serviceProvider.CreateScope();
var scopedService = scope.ServiceProvider.GetRequiredService<IScopedService>();
// ...
}
}
Таким Job
образом, класс контролирует время жизни служб с ограниченной областью действия.
Комментарии:
1. спасибо за ваш ответ, на самом деле я использую версию 3.2.3, которая идеальна. Сейчас я пытаюсь адаптироваться к вашему решению, но у меня есть последняя проблема с доступом к службам на моей работе, когда я ввожу конструктор, который передает в службу, задание, похоже, вообще не вызывается, как мне получить доступ к моей службе, если я не использую новый конструктор (ps: Раньше я решал эту конкретную проблему при переопределении фабрики заданий)
Ответ №2:
Ранее у меня была аналогичная проблема с фоновыми задачами, возможно, вам потребуется создать область видимости.
Я адаптировал этот код и применил его к вашему варианту использования.
public class AspNetCoreJobFactory : SimpleJobFactory
{
IServiceProvider _provider;
public AspNetCoreJobFactory(IServiceProvider provider)
{
_provider = provider;
}
public override IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
using(var serviceScope = _provider.CreateScope())
{
var services = serviceScope.ServiceProvider.
return (IJob)services.GetService(bundle.JobDetail.JobType);
}
}
catch(Exception e)
{
throw new SchedulerException(string.Format("Problem while instantiating job '{0}' from the AspNet Core IOC.", bundle.JobDetail.Key), e);
}
}
}
Комментарии:
1. Я попробовал ваш код, задание больше не выдает исключение, но DbContext, похоже, не работает, все, к чему я пытаюсь получить доступ, пустое или нулевое. есть идеи, почему?
2. @YOUSFIMohamedWalid Хм, странно, я не уверен, я полагаю, вы используете EF Core? Вы можете проверить строку подключения / проверить, что она переводится в SQL или что она работает в базе данных.
3. когда я обращаюсь к тем же методам в той же службе за пределами задания quartz, я получаю свои данные без проблем
4. Приведенный выше код
serviceScope
немедленно удаляет экземпляр. Удаление области удаляет все разрешенные службы, в частности возвращенный объект и его зависимости. Таким образом, вашDbContext
компьютер не находится в пригодном для использования состоянии.5. Спасибо @ChristianHeld, это имело бы смысл, хотя, к сожалению, я не знаю, как изменить код, чтобы он размещался правильно и по-прежнему следовал шаблону OP.