我正在尝试创建一个可以使用 Ninject 加载外部程序集并使用 Quartz.net 按计划运行它们的应用程序。
我已经成功地实现了 Quartz.net 来注入自身,并在同一个程序集中运行基于 IJob 实现的类的作业。这很好用。
我想更进一步,创建一个插件架构。
我创建了一个所有插件都会使用的通用接口,IPlugin,这个接口也实现了 IJob。这在主应用程序中被编译和引用,每个插件都实现它。
using Quartz;
namespace PluginFramework
{
public interface IPlugin : IJob
{ }
}
然后我有一个实现 IPlugin 的测试插件。非常简单,它只是输出一个绿色的时间戳。
using System;
using PluginFramework;
using Quartz;
namespace TestPlugin
{
public class Plugin : IPlugin
{
public void Execute(IJobExecutionContext context)
{
Start();
}
private void Start()
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(DateTime.Now + " - PLUGIN 1");
}
}
}
在我添加 Quartz.net 框架之前,我会像这样加载和执行插件。插件将加载,运行一次,应用程序将按预期结束。
var kernel = new StandardKernel();
var assemblies = Directory.GetFiles(@"E:\Plugins\", "*.dll");
foreach (var assembley in assemblies)
{
kernel.Load(assembley);
}
var plugins = kernel.GetAll<IPlugin>();
foreach (var plugin in plugins)
{
plugin.Execute();
}
现在我需要插件按计划运行,但它仍然必须通过 Ninject 加载,并且主应用程序应该与类型无关,它应该只知道它是一个 IJob 并且能够按照在某些配置中定义的计划运行它. 这是我遇到的麻烦。
我有我的 NinjectJobFactory
public class NinjectJobFactory : IJobFactory
{
private IKernel Kernel { get; set; }
public NinjectJobFactory(IKernel kernel)
{
Kernel = kernel;
}
public IJob NewJob(TriggerFiredBundle bundle)
{
return (IJob)Kernel.Get(bundle.JobDetail.JobType);
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return (IJob) Kernel.Get(bundle.JobDetail.JobType);
}
public void ReturnJob(IJob job)
{
}
}
我的工厂提供商和调度程序提供商。
public class QuartzSchedulerFactoryProvider : Provider<ISchedulerFactory>
{
protected override ISchedulerFactory CreateInstance(IContext context)
{
var properties = new NameValueCollection();
var section = (NameValueCollection)ConfigurationManager.GetSection("quartz");
properties["quartz.scheduler.instanceName"] = section["quartz.scheduler.instanceName"];
properties["quartz.threadPool.type"] = section["quartz.threadPool.type"];
properties["quartz.threadPool.threadCount"] = section["quartz.threadPool.threadCount"];
properties["quartz.threadPool.threadPriority"] = section["quartz.threadPool.threadPriority"];
properties["quartz.jobStore.type"] = section["quartz.jobStore.type"];
properties["quartz.plugin.xml.type"] = section["quartz.plugin.xml.type"];
properties["quartz.plugin.xml.fileNames"] = section["quartz.plugin.xml.fileNames"];
return new StdSchedulerFactory(properties);
}
}
public class QuartzSchedulerProvider : Provider<IScheduler>
{
private readonly IJobFactory _jobFactory;
private readonly IEnumerable<ISchedulerListener> _listeners;
private readonly ISchedulerFactory _schedulerFactory;
public QuartzSchedulerProvider(
ISchedulerFactory schedulerFactory,
IJobFactory jobFactory,
IEnumerable<ISchedulerListener> listeners)
{
_jobFactory = jobFactory;
_listeners = listeners;
_schedulerFactory = schedulerFactory;
}
protected override IScheduler CreateInstance(IContext context)
{
var scheduler = _schedulerFactory.GetScheduler();
scheduler.JobFactory = _jobFactory;
foreach (var listener in _listeners)
{
scheduler.ListenerManager.AddSchedulerListener(listener);
}
return scheduler;
}
}
以及外部 XML 文件中的一些配置。
<schedule>
<job>
<name>Plugin1</name>
<group>Plugins</group>
<description></description>
<job-type>TestPlugin.Plugin, TestPlugin</job-type>
<durable>true</durable>
<recover>false</recover>
</job>
<trigger>
<simple>
<name>Plugin1</name>
<group>Plugins</group>
<job-name>Plugin1</job-name>
<job-group>Plugins</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<repeat-count>-1</repeat-count>
<repeat-interval>1000</repeat-interval>
</simple>
</trigger>
</schedule>
基本上我不知道该怎么做。我已经根据我在谷歌/这里找到的东西尝试了一些东西,但没有任何帮助。任何建议将不胜感激。