Ninject.MVC构造函数注入,其中注入的对象的构造函数接受参数

时间:2012-09-16 22:45:14

标签: c# asp.net-mvc asp.net-mvc-3 dependency-injection ninject

您好我正在使用Ninject.MVC Nuget包和我的MVC3应用程序,并且我有一些构造函数注入的当前绑定设置。

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IUnitOfWork>().To<ERSUnitOfWork>();
        kernel.Bind<IRepository<Recipe>>().To<GenericRepository<Recipe>>();
    }

我的控制器示例如下:

public class RecipesController : Controller
{
    private readonly IUnitOfWork unitOfWork;
    private readonly ERSDbContext context;
    private readonly IRepository<Recipe> recipeRepository;

    public RecipesController(IUnitOfWork unitOfWork, IRepository<Recipe> recipeRepository)
    {
        this.context = new ERSDbContext();
        this.unitOfWork = unitOfWork;
        this.recipeRepository = recipeRepository;
    }
}

我想从控制器中删除私有DBContext属性,并将新的ERSDbContext()传递给ERSUnitOfWork和GenericRepository的构造函数,作为Ninject正在执行的构造函数注入的一部分,但最好保持ERSDbContext类的初始化控制器?

任何有关如何执行此操作的帮助将不胜感激。感谢

我有点希望它不需要我的NinjectWebCommon类必须创建DbContext,我希望它在控制器中初始化。

3 个答案:

答案 0 :(得分:3)

这是你如何抽象依赖关系的问题。

因为您希望控制何时创建DbContext实例,所以您应该有一个工厂来创建特定于类型的DbContext实例,如下所示:

public interface IDbContextFactory
{
     T CreateDbContext<T>() where T : DbContext;
}

(注意,如果您的DI框架很好地处理通用接口上的类型参数,那么您可以使用Entity Framework 5中引入的IDbContextFactory interface

如果您只需要使用默认的无参数构造函数创建类型化DbContext实例,则可以像这样定义您的界面:

public interface IDbContextFactory
{
     T CreateDbContext<T>() where T : DbContext, new();
}

然后定义一个类似的实现:

public class DbContextFactory : IDbContextFactory
{

    #region Implementation of IDbContextFactory

    public T CreateDbContext<T>() where T : DbContext, new()
    {
        // Create a new instance of T and return.
        return new T();
    }

    #endregion
}

如果你需要调用另一个构造函数,那么你要删除new() constraint并且必须使用反射调用(或者,你可以创建一个lambda表达式并根据{{的类型来缓存它) 1}})创建键入的T

从那里,您将DbContext合同与您的实施相关联,并将IDbContextFactory实施注入您的班级,就像您使用任何其他界面一样。

答案 1 :(得分:1)

这是依赖注入的一个好处,它将自动解析所有构造函数参数及其相关的构造函数参数。它为您完成所有这些,只需要定义对象的映射。

所以在你的情况下,你只需这样做:

kerel.Bind<ERSDbContext>().ToSelf();

然后你就可以在你的UoW和Repo上添加ERSDbContext了,你很好。

如果你想对单元测试进行单元测试,那么你需要以某种方式抽象你的上下文,或者像casperOne所提到的那样,或者正如我所提到的那样(你将DbContext从一个通用接口派生出来)然后这样做:

kernel.Bind<IDbContext>().To<ERSDbContext>();

使用DI的一个好处是它可以控制对象的生命周期。如果将DbContext的构造推迟到DI容器之外,则必须手动管理其生命周期,而不是允许DI容器根据生命周期策略(例如在请求结束时自动销毁它)来管理它。

我认为延迟创建上下文没有任何可衡量的好处。我认为你正在做过早的优化。

答案 2 :(得分:0)

由于我的并发问题,我暂时取消了工厂的使用,我正在使用这种方法,因为我的时间很短。

kernel.Bind<ERSDbContext>().ToSelf().InRequestScope();

然后在我的UoW和GenericRepository中,构造函数需要一个ERSDbContext类型的参数。

我想稍后改进这种方法,但现在可行。