我怎样才能做到这一点?我需要调用服务类,但我需要传入参数

时间:2011-05-15 20:19:19

标签: asp.net-mvc nhibernate asp.net-mvc-3 ninject quartz-scheduler

我需要在我的应用程序中调用一些东西来启动我的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>()

3 个答案:

答案 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则间接实例化它们。