从石英工作回调课程

时间:2015-03-16 17:20:53

标签: c# .net autofac quartz.net

我有不同的类作为基类(Worker)的后代。 这些类中的每一个都有它自己的石英作业和触发器和a 回调。

public class Worker1 : Worker, ICallback
{
    IScheduler scheduler;
    public Worker1(IScheduler scheduler)
        : base("Worker1")
    {
        this.scheduler = scheduler;
        IJobDetail job = JobBuilder.Create<MonitorJob>()
            .WithIdentity(name + "Job")
            .Build();
        ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity(name + "Trigger")
            .StartNow()
            .WithSimpleSchedule(x => x
                .WithIntervalInSeconds(1)
                .RepeatForever())
            .Build();
        scheduler.ScheduleJob(job, trigger);
    }

    public void Callback()
    {
        Console.WriteLine(name + " callback " + DateTime.Now.ToLongTimeString());
    }
}

现在我希望触发job1(来自worker1)回调到worker1.callback。 与job2(来自worker2)一样,回调到worker2.callback。

使用autofac我能够将回调注入我的工作 - 但是我只能注入一个共同的回调,而不是我喜欢每个类的回调。

public class MonitorJob : IJob
{
    ICallback callback;

    public MonitorJob(ICallback callback)
    {
        this.callback = callback;
    }

    public void Execute(IJobExecutionContext context)
    {
        callback.Callback();
    }
}

我的主类创建了autofac容器

 container = ConfigureContainer(new ContainerBuilder()).Build();
 using (container.BeginLifetimeScope())
 {
      workers.Add(container.Resolve<Worker1>());
      workers.Add(container.Resolve<Worker2>());
 }
 var factory = container.Resolve<ISchedulerFactory>();
 var scheduler = factory.GetScheduler();
 scheduler.Start();

 internal static ContainerBuilder ConfigureContainer(ContainerBuilder cb)
 {
      cb.RegisterModule(new QuartzAutofacFactoryModule());
      cb.RegisterModule(new QuartzAutofacJobsModule(typeof(QuartzScheduler.MonitorJob).Assembly));
      cb.RegisterType<Worker1>().AsSelf();
      cb.RegisterType<Worker2>().AsSelf();
      return cb;
  }

Autofac会创建作业,也可以通过回调注入它,但是我希望从“拥有”作业的工人类中获得正确的回调。

这怎么可能?

否则我需要以某种方式从一个公共回调传播到相应的工人类。

提前谢谢

3 个答案:

答案 0 :(得分:0)

Autofac无法知道如何绑定 ICallbackIJob。怎么想绑定他们?

最简单的解决方案是在这两个类之间引入依赖

public class MonitorJob : IJob
{
    public MonitorJob(Worker1 worker1)
    {
        this._worker1 = worker1;
    }

    private readonly Worker1 _worker1;

    public void Execute(IJobExecutionContext context)
    {
        this._worker1.Callback();
    }
}

如果无法使用Keyed service

public class MonitorJob : IJob
{
    public MonitorJob([WithKey("Worker1")]ICallback callback)
    {
        this._callback = callback;
    }

    private readonly ICallback _callback;

    public void Execute(IJobExecutionContext context)
    {
        this._callback.Callback();
    }
}

,您必须以cb.RegisterType<Worker1>().Keyed<ICallback>("Worker1")

的方式注册

如果仍然无法以这种方式修改代码,您可以创建一个新模块来添加参数:

public class CallbackModule : Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
    {
        if (registration.Services.OfType<TypedService>()
                                 .Any(s => s.ServiceType == typeof(IJob)))
        {
            registration.Preparing += (sender, e) =>
            {
                // bind ICallback and IJob here
                if (registration.Activator.LimitType == typeof(Job1))
                {
                    e.Parameters = e.Parameters
                                    .Concat(new TypedParameter[] { TypedParameter.From<ICallback>(e.Context.Resolve<Worker1>()) });
                }
            };
        }
    }
}

注册可以这样做:

    ContainerBuilder cb = new ContainerBuilder();
    cb.RegisterModule(new CallbackModule());
    cb.RegisterType<Worker1>().As<ICallback>().AsSelf();
    cb.RegisterType<Worker2>().As<ICallback>().AsSelf();
    IContainer container = cb.Build();

顺便说一句,以下代码包含错误:

using (container.BeginLifetimeScope())
{
  workers.Add(container.Resolve<Worker1>());
  workers.Add(container.Resolve<Worker2>());
}

您创建了一个新的ILifetimeScope但不使用它。应该使用以下代码:

using (ILifetimeScope scope = container.BeginLifetimeScope())
{
  workers.Add(scope.Resolve<Worker1>());
  workers.Add(scope.Resolve<Worker2>());
}

答案 1 :(得分:0)

如果您希望在调用execute方法时收到通知,则可以为此实现JobListener。您可以为所有作业或多个侦听器创建一个侦听器,可能为每个作业类型创建一个侦听器,然后应用适当的匹配器。这里有一个链接,可能对工作听众和听众的更多细节有用:Quartz.Net Job Listeners, Part 3 of Quartz.net Listeners in detail

答案 2 :(得分:0)

我成功创建了一个通用的工作:

public class MonitorJob<T> : IJob where T:IWorker
{
    T worker;

    public MonitorJob(T worker)
    {
        this.worker = worker;
    }

    public void Execute(IJobExecutionContext context)
    {
        worker.Callback();
    }
}

在我的自定义工作者类中,我为该worker创建了监视器作业:

public Worker1(IScheduler scheduler)
{
   this.scheduler = scheduler;

   IJobDetail job = JobBuilder.Create<MonitorJob<Worker1>>()
      .WithIdentity(name + "Job")
      .Build();
        [...]
 }

所以正确的回调类将通过以下方式解决:

container.RegisterType<Worker1>().AsSelf().SingleInstance();
container.RegisterType<MonitorJob<Worker1>>().AsSelf();

[...]
workers.Add(scope.Resolve<Worker1>());

所以总是为每个单独的工作执行正确的回调。