我在3层架构上有一个带有Unity依赖注入的MVC4 .Net Web应用程序,我希望每天都能提供一个版本并发送一些邮件.为此我想在Application_start中使用Quartz Scheduler,因为依赖注入windows服务不是一个好选择.
这是我在application_start中的代码.
// construct a scheduler factory ISchedulerFactory schedFact = new StdSchedulerFactory(); IScheduler sched = schedFact.GetScheduler(); sched.Start(); IJobDetail dailyUserMailJob = new JobDetailImpl("DailyUserMailJob",null,typeof(SchedulerJob)); // fire every time I open App/EveryDay ITrigger dailyUserMailTrigger = new SimpleTriggerImpl("DailyUserMailTrigger",1,new TimeSpan(1,0)); sched.ScheduleJob(dailyUserMailJob,dailyUserMailTrigger);
这是我的工作代码:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using EvaluationMvc.Bll.Contracts; using Quartz; using Quartz.Impl; namespace EvaluationMvc.Utils { public class SchedulerJob : IJob { private IEvaluationBus _iEvaluationBus; public SchedulerJob(IEvaluationBus iEvaluationBus) { //Dependency injection _iEvaluationBus = iEvaluationBus; } public void Execute(IJobExecutionContext context) { _iEvaluationBus.testingArchitecture(); // Sends a test mail. } } }
但是我的工作从未执行过,可能是什么问题?
解决方法
必须将Quartz.net Scheduler创建为
singleton.
您可以安装Unity.MVC4 NuGet Package.
它将创建一个Bootstrapper类,它看起来像这样:
public static class Bootstrapper { public static IUnityContainer Initialise() { var container = BuildUnityContainer(); DependencyResolver.SetResolver(new UnityDependencyResolver(container)); return container; } private static IUnityContainer BuildUnityContainer() { var container = new UnityContainer(); // Register your interfaces here. RegisterTypes(container); return container; } public static void RegisterTypes(IUnityContainer container) { } }
然后你必须创建自己的JobFactory实现.这article可能对你有帮助,this one值得一读:
public class UnityJobFactory: IJobFactory { private readonly IUnityContainer container; static UnityJobFactory() { } public UnityJobFactory(IUnityContainer container) { this.container = container; } public IJob NewJob(TriggerFiredBundle bundle,IScheduler scheduler) { var jobDetail = bundle.JobDetail; var jobType = jobDetail.JobType; try { return this.container.Resolve(jobType) as IJob; } catch (Exception ex) { throw new SchedulerException(string.Format( CultureInfo.InvariantCulture,"Cannot instantiate class '{0}'",new object[] { jobDetail.JobType.FullName }),ex); } } public void ReturnJob(IJob job) { // Nothing here. Unity does not maintain a handle to container created instances. } }
和你自己的StdSchedulerFactory实现:
public class UnitySchedulerFactory : StdSchedulerFactory { private readonly UnityJobFactory unityJobFactory; public UnitySchedulerFactory(UnityJobFactory unityJobFactory) { this.unityJobFactory = unityJobFactory; } protected override IScheduler Instantiate(QuartzSchedulerResources rsrcs,QuartzScheduler qs) { qs.JobFactory = this.unityJobFactory; return base.Instantiate(rsrcs,qs); } }
回到你的Unity Bootstrapper,你必须注册你的接口:
private static IUnityContainer BuildUnityContainer() { var container = new UnityContainer(); container.RegisterType<ISchedulerFactory,UnitySchedulerFactory>(new ContainerControlledLifetimeManager()); container.RegisterType<IScheduler>(new InjectionFactory(c => c.Resolve<ISchedulerFactory>().GetScheduler())); container.RegisterType<IQuartzScheduler,QuartzScheduler>(new ContainerControlledLifetimeManager()); container.RegisterType<IEvaluationBus,EvaluationBus>(); RegisterTypes(container); return container; }
我已经将我的服务调度程序包装在一个类中,以便我可以创建它单例:
public interface IQuartzScheduler { void Run(); void Stop(); }
和:
public class QuartzScheduler : IQuartzScheduler { private readonly ISchedulerFactory SchedulerFactory; private readonly IScheduler Scheduler; public QuartzScheduler(ISchedulerFactory schedulerFactory,IScheduler scheduler) { this.SchedulerFactory = schedulerFactory; this.Scheduler = scheduler; } public void Run() { IJobDetail dailyUserMailJob = new JobDetailImpl("DailyUserMailJob",typeof(Scheduler.SchedulerJob)); // fire every time I open App/EveryDay ITrigger dailyUserMailTrigger = new SimpleTriggerImpl("DailyUserMailTrigger",10,new TimeSpan(0,20)); this.Scheduler.ScheduleJob(dailyUserMailJob,dailyUserMailTrigger); this.Scheduler.Start(); } public void Stop() { this.Scheduler.Shutdown(false); } }
正如您在本课程中看到的,我将创建我的作业/触发器并启动调度程序.
现在在您的Application_Start(global.asax)中,您可以“引导”Unity容器,获取服务调度程序并运行它.
var unityContainer = Infrastructure.Bootstrapper.Initialise(); unityContainer.Resolve<IQuartzScheduler>().Run();
您可以在此link(QuartzWithUnity)之后找到工作示例.