Ninject Singleton for MVC Data Repository

时间:2011-04-08 20:26:13

标签: asp.net-mvc ninject repository-pattern

在我的MVC3应用程序中,我有一个IDataRepository接口,我的所有控制器都会引用它来授予他们访问数据层的权限。还有一个DataRepository类,它实现了特定数据源的IDataRepository(在我的例子中是一个nHydrate派生的实体框架)。 DataRepository类采用单个参数,该参数是底层数据库的连接字符串。

我已经使用以下绑定成功地将nInject用于控制器类到IoC:

kernel.Bind<IDataRepository>()
    .To<DataRepository>()
    .WithConstructorArgument("connectionString", DataRepositoryBase.GetConnectionString());

今天我读到了关于nInject作用域的内容,我认为安排一些事情是有用的,这样每个请求只创建了一个DatabaseRepository实例(我认为这样会更有效,尽管有EF我不是当然)。

不幸的是,我似乎无法弄清楚如何正确实现模式。例如,这不起作用:

kernel.Bind<DataRepository>()
    .ToSelf()
    .InRequestScope()
    .WithConstructorArgument("connectionString", DataRepositoryBase.GetConnectionString());

kernel.Bind<IDataRepository>()
    .To<DataRepository>();

我的想法是,这只会创建一个DataRepository实例,它将在IDataRepository的所有引用中使用。错误消息抱怨找不到connectionString参数的匹配项,并且DataRepository不可自我绑定。我尝试了一些变体,但是当我能够使它工作时,没有遵循单例模式(即,我可以在调试器中看到正在创建多个DataRepository实例)。

我在这里遗漏了一些明显的东西:)。

---附录--- 不幸的是,该建议并未阻止在同一请求中创建多个实例。

要清楚,我尝试的是:

public class BaseControllerModule : NinjectModule
{
    public override void Load()
    {
        Bind<IDataRepository>().To<DataRepository>().InRequestScope()
        .WithConstructorArgument("connectionString", DataRepositoryBase.GetConnectionString());
    }
}

我正在监控的是构造函数:

public DataRepository( string connectionString )
    : base(connectionString)
{
}

- 更多信息#2 -

这是Ninject为我解决的类的布局:

public class DataRepositoryBase
{
    protected DataRepositoryBase( string connectionString )
    {}
    public static string GetConnectionString() {}
}
public class DataRepository : DataRepositoryBase, IDataRepository
{
    public DataRepository( string connectionString )
        : base(connectionString)
    {}
}

我遗漏了实施细节,但希望这能描绘出更好的画面。

仔细观察,我想知道我是否因为ConnectionString是DataRepository及其基类DataRepositoryBase的构造函数参数而导致问题。 Ninject会不会在调用基类构造函数时解析connectionString?

P.S。我姗姗来迟地意识到我不需要DataRepositoryBase,因为它的功能可以合并到DataRepository中。我已经这样做了,但我仍然在DataRepository的构造函数中多次调用,看似是一个请求。

p2.s。为了好玩,我尝试在Ninject绑定定义中声明InSingletonScope()。这工作 - 当首次访问应用程序时,DataRepository的构造函数现在只被调用一次。但我不认为在MVC应用程序中拥有单身人士是个好主意。这似乎会导致应用程序的“状态”被“锁定”在内存中。

---更多信息---

问题似乎与我设计MVC应用程序的方式有关。我假设从浏览器返回服务器的单个请求经常导致多个请求按顺序处理(我正在观看在MvcApplication类中触发的BeginRequest事件)。似乎每次我转换到不同的控制器时都会生成新的请求(例如,通过RedirectToAction)。我想这是有道理的,但这意味着Ninject的InRequestScope不会完全按我的意愿行事。

但它也让我想知道我是否只是设计了错误的应用程序。看起来我应该将可能在浏览器调用中调用的所有操作方法分组到单个控制器中。相反,我已经根据它们如何适应我的应用程序的概念模型来组织动作方法。

2 个答案:

答案 0 :(得分:4)

这两个绑定说: 当请求DataRepository时,请为请求中的所有出现重用该实例,并将连接字符串设置为DataRepositoryBase.GetConnectionString()。

但是当请求IDataRepository时,为每次出现创建一个新实例,让Ninject决定它为连接字符串注入的内容。

您真正想要的是通过将InRequestScope添加到第一个代码段来完成。

答案 1 :(得分:1)

单身人士不够吗?

kernel.Bind<IDataRepository>()
    .To<DataRepository>()
    .InSingletonScope()
    .WithConstructorArgument("connectionString", DataRepositoryBase.GetConnectionString());

RequestScope不是单身,它意味着每个用户的呼叫都是分开的对象。

顺便说一下,我认为真正的存储库不应该是单例 - 它应该遵循Unit of Work模式,这意味着它的生命周期应代表一个更高级别的数据操作,并且连接本身应该更低级别比存储库。