Мы используем такой метод в нашем файле Global.asax.cs именно для этой цели (он вызывается из Application_Start:
private static void SetupScheduling(IKernel kernel)
{
var scheduler = SchedulerUtil.Scheduler;
scheduler.JobFactory = kernel.Get<IJobFactory>();
scheduler.Start();
}
И мы IJobFactory
связаны со следующим классом:
public class QuartzJobFactory : IJobFactory
{
private readonly IObjectFactory<IJob> _jobFactory;
private readonly LogService _logService;
public QuartzJobFactory(IObjectFactory<IJob> jobFactory,
LogService logService)
{
_jobFactory = jobFactory;
_logService = logService;
}
/// <summary>
/// Called by the scheduler at the time of the trigger firing, in order to
/// produce a <see cref="T:Quartz.IJob"/> instance on which to call Execute.
/// </summary>
/// <remarks>
/// <p>It should be extremely rare for this method to throw an exception -
/// basically only the the case where there is no way at all to instantiate
/// and prepare the Job for execution. When the exception is thrown, the
/// Scheduler will move all triggers associated with the Job into the
/// <see cref="F:Quartz.TriggerState.Error"/> state, which will require human
/// intervention (e.g. an application restart after fixing whatever
/// configuration problem led to the issue wih instantiating the Job.
/// </p>
/// </remarks>
/// <param name="bundle">The TriggerFiredBundle from which the <see cref="T:Quartz.JobDetail"/>
/// and other info relating to the trigger firing can be obtained.
/// </param><throws>SchedulerException if there is a problem instantiating the Job. </throws>
/// <returns>
/// the newly instantiated Job
/// </returns>
public IJob NewJob(TriggerFiredBundle bundle)
{
Type jobType;
try
{
Require.ThatArgument(bundle != null);
Require.ThatArgument(bundle.JobDetail != null);
jobType = bundle.JobDetail.JobType;
}
catch (Exception e)
{
// This shouldn't ever happen, but if it does I want to know about it.
_logService.LogCritical(() => e.ToString());
throw;
}
try
{
return _jobFactory.GetObject(jobType);
}
catch (Exception e)
{
_logService.LogCritical(() => "An exception was thrown while creating job of type {0}: {1}"
.With(jobType, e));
throw;
}
}
}
И IObjectFactory - это простой интерфейс, который просто абстрагирует ядро, поэтому мы не зависим от Ninject везде:
/// <summary>
/// Similar to IFactory, but this factory produces types based on a dynamic
/// <see cref="Type"/> object. If the given Type object is not of the given
/// "T" type, an exception will be thrown.
/// </summary>
/// <typeparam name="T">A parent-level type representing what sort of values
/// are expected. If the type could be anything, try using <see cref="object"/>
/// </typeparam>
public interface IObjectFactory<out T>
{
T GetObject(Type type);
}
IObjectFactory
затем связывается с таким классом:
/// <summary>
/// This implementation of the generic <see cref="IFactory{T}"/> and
/// <see cref="IObjectFactory{T}"/> classes uses Ninject to supply instances of
/// the given type. It should not be used explicitly, but will rather be used
/// by the DI framework itself, to provide instances to services that depend on
/// IFactory objects.
/// This implementation takes the injection context as a constructor argument, so that
/// it can reuse elements of the context when it is asked to supply an instance
/// of a type.
/// In order for this to work, you will need to define bindings from <see cref="IFactory{T}"/>
/// and <see cref="IObjectFactory{T}"/> to this class, as well as a binding from
/// <see cref="IContext"/> to a method or factory that returns the current binding
/// context.
/// </summary>
/// <typeparam name="T">The Type of the service to be produced by the Get method.</typeparam>
public class InjectionFactory<T> : IFactory<T>, IObjectFactory<T>
{
private readonly IKernel _kernel;
private readonly IParameter[] _contextParameters;
/// <summary>
/// Constructs an InjectionFactory
/// </summary>
/// <param name="injectionContext">The context in which this injection is taking place.</param>
public InjectionFactory(IContext injectionContext)
{
_contextParameters = injectionContext.Parameters
.Where(p => p.ShouldInherit).ToArray();
_kernel = injectionContext.Kernel;
}
public T Get()
{
try
{
return _kernel.Get<T>(_contextParameters.ToArray());
}
catch (Exception e)
{
throw e.Wrap(() => "An error occurred while attempting to instantiate an object of type <{0}>".With(typeof(T)));
}
}
public T GetObject(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (!typeof (T).IsAssignableFrom(type))
{
throw new InvalidCastException(type.FullName + " is not a child type of " + typeof (T).FullName);
}
try
{
return (T)_kernel.Get(type, _contextParameters);
}
catch (Exception e)
{
throw e.Wrap(() => "An error occurred while attempting to instantiate an object of type <{0}>".With(typeof(T)));
}
}
}
... используя привязку, которая выглядит следующим образом:
Bind(typeof (IObjectFactory<>)).To(typeof (InjectionFactory<>));
// Injection factories ask for the injection context.
Bind(typeof (IContext)).ToMethod(c => c.Request.ParentContext);
Таким образом, общий эффект состоит в том, что мы используем ядро Ninject для создания IJobFactory, который использует инжектор конструктора для получения IObjectFactory<IJob>
, который вызывается для получения любых IJob
s, которые требуются Quartz. Поэтому эти классы заданий могут использовать инжекцию на основе конструктора, и Ninject косвенно их создает.