2016年5月12日 星期四

【Quartz.net】Using Autofac to build IJob implement class

這篇起源於我裝好 Quartz 實作 IJob 到一批服務之後,卻有一大半沒被驅動起來,卻又不是全部,而且 IJobListener 也看不到沒跑起來的那些服務。

花了超過半天的時間歸結了數個類別之後,才找到問題,簡化來看,跑不起來的長的像
public class MyJob1 : IJob
{
    public string Input { get; set; }

    public MyJob1(string input)
    {
        Input = input;
    }

    public void Execute(IJobExecutionContext context)
    {
        Console.WriteLine("【" + Input + "】" + context.Trigger.Key.Name);
    }
}

而可以跑起來的則是
public class MyJob2 : IJob
{
    public void Execute(IJobExecutionContext context)
    {
        Console.WriteLine("【MyJob2】" + context.Trigger.Key.Name);
    }
}

這樣就比較明顯了,差別就是建構子,石英自己去建 Job 的時候需要一個空白參數的建構子,沒有的話根本連 Job 都沒建,沒跑,Listener 當然也不會有錯誤訊息,如果加個
public class MyJob1 : IJob
{
    public string Input { get; set; }

    public MyJob1()
    {
        Input = "MyJob1";
    }

    public MyJob1(string input)
    {
        Input = input;
    }

    public void Execute(IJobExecutionContext context)
    {
        Console.WriteLine("【" + Input + "】" + context.Trigger.Key.Name);
    }
}
就可以跑起來

可,問題是我實際上需要跑起來的是有傳入 input 的那個,而且專案裡東西都是用 Autofac 建的,只有這邊改做法顯然不對。 查了一下 Quartz 要定義 Job 的建構過程細節要自己去實作 IJobFactory 然後再指派給 IScheduler。
sealed class AutofacJobFactory : IJobFactory
{
    IContainer _container;

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

    /// <summary>Core, build IJob instance</summary>
    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        // use bundle.JobDetail.Key.Name to decide which specific class to build
        return _container.ResolveKeyed<IJob>(bundle.JobDetail.Key.Name);
    }

    public void ReturnJob(IJob job)
    {
    }
}

在 IScheduler 部分
var container = builder.Build();
sched.JobFactory = new AutofacJobFactory(container);
// start the schedule
sched.Start();

當然 Autofac 端註冊實也要記得 IJob 跟實作 class 的對應,還有建構子參數的傳入等
builder.RegisterAssemblyTypes(asmCollToReg.ToArray())
    .Where(t => t.Name == typeImplIJob.Name) // decide to build which IJob Impl class's instance
    .Keyed<IJob>(typeImplIJob.Name) // para match to class name
    .WithParameter("input", typeImplIJob.Name + " :D"); // para for ctor, para1 is variable name

GitHub: full proj
ref:DI&Quartzctor paracondition of RegisterAssemblyTypes

沒有留言:

張貼留言