【问题标题】:How do I create a Quartz.NET’s job requiring injection with autofac如何创建需要使用 autofac 进行注入的 Quartz.NET 作业
【发布时间】:2013-06-04 01:16:57
【问题描述】:

我正在尝试让 Quartz.net (2.1.2) 与 IoC 容器 (autofac) 一起工作,因为我有需要在计划作业中使用的服务。我在这个主题上找到了类似的帖子,但我似乎找不到具有 autofac 特定注册示例的帖子。

以下帖子涉及我遇到的相同问题:

How to schedule task using Quartz.net 2.0?

但是,我认为我缺少的部分是答案说“并且不要忘记在 IoC 容器中注册作业”。我不确定如何准确地做到这一点,因为到目前为止我尝试过的所有方法都没有奏效。

在以下示例中,“HelloJob”将运行,但每当我尝试将 releaseService 注入“ReleaseJob”时,它都会拒绝运行。

更新: 我在 DependencyRegistration.cs 部分中标记了我认为问题所在的代码。

更新 2: 一些与我需要做的事情相关并且可能会有所帮助的相关链接(我已经完成了所有这些,但仍然无法弄清楚如何使用 autofac):

如何以 PRO 方式使用 Quartz.NET? - 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 和 Simple Injector 进行构造函数注入 - Constructor injection with Quartz.NET and Simple Injector

ASP.Net MVC 3、Ninject 和 Quartz.Net - 如何? - ASP.Net MVC 3, Ninject and Quartz.Net - How to?

以下是相关代码:

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();
    }
}

【问题讨论】:

  • 您为我节省了弄清楚这一点的时间。非常感谢托马斯。

标签: asp.net-mvc-3 autofac quartz.net-2.0


【解决方案1】:

我终于找到了问题所在。

我的发布服务正在使用一个数据存储库,该存储库是在不同的范围内创建的。

我通过创建一个新的测试服务发现了这一点,该服务只返回一个字符串,并且被注入到一个石英作业中。

发现这一点后,我更改了发布服务调用的存储库的范围,然后发布服务开始在石英作业中工作。

对于任何看到这个问题并试图帮助我的人,我深表歉意。因为没有列出发布服务的代码,所以很难弄清楚哪里出了问题。

我已经用我用于石英和 autofac 的最终工作绑定更新了代码。

【讨论】:

  • 嗨,Thomas - 很抱歉恢复旧帖子,但您有一个示例说明您如何更改服务范围以解决此问题。我陷入了同样的陷阱,我在依赖注入方面没有太多经验,无法让它工作:/
  • 我相信它正在将范围从不起作用的“InstancePerHttpRequest”更改为在存储库和 releaseservice 模块中起作用的“InstancePerLifetimeScope”。
【解决方案2】:

问题是您的 AutofacJobFactory 没有创建 ReleaseJob(您正在使用 JobBuilder.Create&lt;ReleaseJob&gt;() 执行此操作),因此 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&lt;ReleaseJob&gt;(),而是通过 JobDetailImpl 对象传递要创建的作业的详细信息,并由调度程序的作业工厂(AutofacJobFactory)负责实例化作业和依赖注入可能发生。

【讨论】:

  • 我做了你推荐的改变。我删除了 JobBuilder.Create 并将其替换为您的示例。但是,行为仍然相同。 HelloJob 运行,但 ReleaseJob 不运行。
  • 我假设现在正在调用 AutofacJobFactory.NewJob() 方法?如果是这样,它与您的绑定有问题。作为测试,您可以将相关标记的问题行更改为builder.RegisterType&lt;ReleaseJob&gt;.As&lt;IJob&gt;();,并将下一行更改为JobDetailImpl jobDetail = new JobDetailImpl("1Job", null, typeof(IJob )); 请注意,这将测试现在是否正在解析绑定,但如果您想实例化,您将需要一个抽象工厂多种IJob
  • 我在 AutofacJobFactory.NewJob() 上放了一个断点。它确实为 HelloJob 调用,但似乎从未从 ReleaseJob 触发。我还更改了 IJob 中提到的构建器和作业类型,并且一次只运行一个。 HelloJob 再次工作,ReleaseJob 没有。感谢您迄今为止提供的所有帮助 - 我对绑定不是很有经验,并且一直怀疑它们是这里的问题,我只是不确定接下来要尝试什么才能让它们工作。
猜你喜欢
  • 2021-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-13
相关资源
最近更新 更多