我需要在我的应用程序中调用一些东西来启动我的quartz.net调度程序。
问题是我需要将存储库传递到我的服务层,通常使用ninject和依赖注入完成。
//global.aspx
public class MvcApplication : System.Web.HttpApplication
{
private readonly IScheduledRemindersService scheduledRemindersService;
public MvcApplication(IScheduledRemindersService
scheduledRemindersService)
{
this.scheduledRemindersService = scheduledRemindersService;
}
protected void Application_Start()
{
//other default stuff here like mvc routers.
scheduledRemindersService.RemindersSchedule();
}
}
private readonly IReminderRepo reminderRepo;
public ScheduledRemindersService(IReminderRepo reminderRepo)
{
this.reminderRepo = reminderRepo;
}
private readonly IReminderRepo reminderRepo;
public ScheduledRemindersService(IReminderRepo reminderRepo)
{
this.reminderRepo = reminderRepo;
}
我有NHibernate设置为这样当看起来IReminderRepo它shoudl绑定它并在IReminderRepo我有
private readonly ISession session;
public ReminderRepo(ISession session)
{
this.session = session;
}
这也会通过nhibernate自动绑定。
这不起作用,因为global.aspx只允许没有参数构造函数。
那么如何为这些接口注入正确的类呢? 特别是nhibernate会话,这是我需要的最重要的事情。
修改
public class NhibernateSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var sessionFactory = new NhibernateSessionFactory();
return sessionFactory.GetSessionFactory();
}
}
public class NhibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
}
}
//在global.aspx
中 protected IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new NhibernateModule(),
new ServiceModule(),
new RepoModule(),
};
return new StandardKernel(modules);
}
//在RepoModule()
中 Bind<IReminderRepo>().To<ReminderRepo>();
//在serviceModule
中 Bind<IScheduledRemindersService>().To<ScheduledRemindersService>()
答案 0 :(得分:0)
我认为你不太了解IoC。当你说ISession将通过NHibernate自动绑定时 - 你在想什么? NHibernate不会为您管理。会话生活方式管理是您的领域。
我认为没有足够的代码可以真正帮助你。服务以及存储库需要由您的IoC管理才能将一个注入另一个 - 除非您直接引用IoC - 这是不推荐的。
答案 1 :(得分:0)
您应该从IoC容器中获取IScheduledRemindersService的实例。容器应该在创建/解析实例时负责为您注入所有依赖项。
我不熟悉NInject所以我不能告诉你应该怎么做,但你应该做的事情是:
protected void Application_Start()
{
// 1- register IoC container
// 2- resolve instance of IScheduledRemindersService
// 3- invoke RemindersService() method on instance
}
答案 2 :(得分:0)
我们在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>
,调用它来生成Quartz需要的任何IJob
。因此,这些作业类可以使用基于构造函数的注入,而Ninject则间接实例化它们。