Как создать задание Quartz.NET, требующее инъекции с помощью autofac

Я пытаюсь заставить Quartz.net(2.1.2) работать с контейнером IoC (autofac), поскольку у меня есть службы, которые мне нужно использовать в запланированных заданиях. Я нашел похожие сообщения по этому вопросу, но я не могу найти его с конкретным примером регистрации для autofac.

Следующая публикация касается той же проблемы, что и я:

Как планировать задачу с помощью Quartz.net 2.0?

Тем не менее, часть, которую я считаю недостающей, - это когда в ответе говорится "И не забудьте зарегистрировать задание в контейнере IoC". Я не уверен, как это сделать точно, поскольку все, что я пробовал до сих пор, не сработало.

В следующем примере запускается "HelloJob", но всякий раз, когда я пытаюсь внедрить releaseService в "ReleaseJob", он отказывается запускаться.

Update: Я отметил код в разделе DependencyRegistration.cs, где я считаю, что проблема.

Обновление 2: Некоторые связанные ссылки, которые связаны с тем, что мне нужно делать и могут помочь (я уже прошел через все, но все еще не могу понять, как это работает с autofac):

КАК использовать Quartz.NET в PRO? - http://blog.goyello.com/2009/09/21/how-to-use-quartz-net-in-pro-way/

Autofac и Quartz.NET - http://blog.humann.info/post/2013/01/30/Autofac-and-QuartzNET.aspx

Встраивание конструктора с Quartz.NET и простым инжектором - Ввод конструктора с Quartz.NET и простым инжектором

ASP.Net MVC 3, Ninject и Quartz.Net - Как это сделать? - ASP.Net MVC 3, Ninject и Quartz.Net - Как?

Вот соответствующий код:

Global.asax

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        var dependencyRegistration = new DependencyRegistration();
        dependencyRegistration.Register();

        ModelValidatorProviders.Providers.Clear();
        ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(new ValidatorFactory()));

        DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
    }

DependencyRegistration.cs

public class DependencyRegistration
{
    public void Register()
    {
        var builder = new ContainerBuilder();

        builder.RegisterControllers(Assembly.GetExecutingAssembly());
        builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());

        // Validation
        builder.RegisterType<ValidatorFactory>()
            .As<IValidatorFactory>()
            .InstancePerHttpRequest();

        AssemblyScanner findValidatorsInAssembly = AssemblyScanner.FindValidatorsInAssembly(Assembly.GetExecutingAssembly());
        foreach (AssemblyScanner.AssemblyScanResult item in findValidatorsInAssembly)
        {
            builder.RegisterType(item.ValidatorType)
                .As(item.InterfaceType)
                .InstancePerHttpRequest();
        }

        // Schedule
        builder.Register(x => new StdSchedulerFactory().GetScheduler()).As<IScheduler>();

        // Schedule jobs
        builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).Where(x => typeof(IJob).IsAssignableFrom(x));

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        //Schedule
        IScheduler sched = container.Resolve<IScheduler>();
        sched.JobFactory = new AutofacJobFactory(container);
        sched.Start();

        IJobDetail job = JobBuilder.Create<ReleaseJob>()
                .WithIdentity("1Job")
                .Build();

        ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity("1JobTrigger")
            .WithSimpleSchedule(x => x
                .RepeatForever()
                .WithIntervalInSeconds(5)
            )
            .StartNow()
            .Build();

        sched.ScheduleJob(job, trigger);

        job = JobBuilder.Create<HelloJob>()
               .WithIdentity("2Job")
               .Build();

        trigger = TriggerBuilder.Create()
            .WithIdentity("2JobTrigger")
            .WithSimpleSchedule(x => x
                .RepeatForever()
                .WithIntervalInSeconds(5)
            )
            .StartNow()
            .Build();

        sched.ScheduleJob(job, trigger);
    }
}

JobFactory.cs

public class AutofacJobFactory : IJobFactory
{
    private readonly IContainer _container;

    public AutofacJobFactory(IContainer container)
    {
        _container = container;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        return (IJob)_container.Resolve(bundle.JobDetail.JobType);
    }

    public void ReturnJob(IJob job)
    {
    }
}

ReleaseJob.cs

public class ReleaseJob : IJob
{
    private readonly IReleaseService _releaseService;

    public ReleaseJob(IReleaseService releaseService)
    {
        this._releaseService = releaseService;
    }

    public void Execute(IJobExecutionContext context)
    {
        Debug.WriteLine("Release running at " + DateTime.Now.ToString());
    }
}

public class HelloJob : IJob
{
    public void Execute(IJobExecutionContext context)
    {
        Debug.WriteLine("Hello job at " + DateTime.Now.ToString());
    }
}

ReleaseServiceModel.cs

public class ReleaseServiceModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<ReleaseService>()
            .As<IReleaseService>()
            .InstancePerLifetimeScope();
    }
}

Ответы

Ответ 1

Наконец-то я выяснил, в чем проблема.

В моей службе выпуска использовался репозиторий данных, который создавался с другой областью.

Я обнаружил это, создав новую тестовую службу, которая ничего не делала, но возвращала строку, и это работало, будучи введенным в кварцевое задание.

Обнаружив это, я изменил область репозитория, вызванную службой release, а затем служба выпуска начала работать внутри задания кварца.

Приношу свои извинения всем, кто посмотрел на этот вопрос, чтобы попытаться помочь мне. Поскольку код службы выпуска не был указан, было бы сложно выяснить, что не так.

Я обновил код с окончательными рабочими привязками, которые я использовал для кварца с autofac.

Ответ 2

Проблема заключается в том, что ваш AutofacJobFactory не создает ReleaseJob (вы делаете это с помощью JobBuilder.Create<ReleaseJob>() вместо этого), поэтому контейнер IoC не знает об импотенции, потому что инъекция зависимости не может произойти.

Следующий код должен работать:

sched = schedFact.GetScheduler();
sched.JobFactory = new AutofacJobFactory(container);
sched.Start();

// construct job info
JobDetailImpl jobDetail = new JobDetailImpl("1Job", null, typeof(ReleaseJob ));

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("1JobTrigger")
    .WithSimpleSchedule(x => x
        .RepeatForever()
        .WithIntervalInSeconds(5)
    )
    .StartNow()
    .Build();

sched.ScheduleJob(jobDetail, trigger);

Обратите внимание, что в этом примере мы больше не используем JobBuilder.Create<ReleaseJob>(), вместо этого мы передаем детали задания, которое должно быть создано с помощью объекта JobDetailImpl, и, выполняя это, задание планировщика (AutofacJobFactory) отвечает за создание экземпляра задания и инъекция зависимостей.