2015-03-16 5 views
0

У меня есть разные классы как потомки базового класса (Рабочий). Каждый из этих классов имеет свое собственное кварцевое задание и триггер и обратный вызов .Обратный вызов класса из задания кварца

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 (from worker1) был обратный вызов employee1.callback. То же самое с job2 (from 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 создает работу, а также может вводить его с обратным вызовом, однако я хочу право обратного вызова из класса рабочего, который «владеет» работой ,

Как это возможно?

В противном случае мне нужно каким-то образом распространить один общий обратный вызов на соответствующий рабочий класс.

Спасибо заранее

ответ

0

Autofac не имеет возможности узнать, как связываютICallback и IJob. Как бы связать их?

Самым простым решением является введение зависимость между этими 2 классами

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

Спасибо за ваш ответ, однако обязательный ICallback для IJob уже работал, как уже упоминалось в моем вопросе, но, конечно, только для одного экземпляра обратного вызова, где мне пришлось бы распространять событие на соответствующий рабочий экземпляр. Я не хочу связывать его непосредственно с рабочим1, поскольку он также должен запускать другие экземпляры рабочих, например. worker2.callback до рабочегоN. Поэтому я думаю, что подход Keyed тоже не подойдет. Я мог бы создать работу на одного работника, полученного из моего общего MonitorJob, который можно было бы решить, но я надеялся, что это будет возможно с помощью общего подхода. – vknapp

+0

Я не уверен, что понял ваши потребности. Когда запускается «MonitorJob», который должен использоваться «ICallback»? Все они ? если это так, вы можете добавить зависимость от 'IEnumerable ', если вы хотите указать конкретный, как вы указываете, какой 'ICallback' должен использовать' IJob'? –

+0

У каждого работника есть свой собственный монитор, который должен назвать его собственным обратным вызовом. Мне удалось получить Worker1Job от Monitorjob, в котором, как вы сказали, есть рабочий класс с clallback. Недостаток - мне нужна работа для каждого рабочего класса. однако это работает. – vknapp

0

Если вы хотите получить уведомление, когда вызывается метод выполнения, вы можете реализовать JobListener для этого. Вы можете создать один прослушиватель для всех заданий или нескольких слушателей, по одному для каждого типа заданий, а затем применить соответствующий соединитель.Вот ссылка, которая может быть полезной с более подробной информацией о слушателях работы и слушателях в целом: Quartz.Net Job Listeners, Part 3 of Quartz.net Listeners in detail

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

В моем классе пользовательские рабочего я создаю работу монитора для этого работник:

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

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