【问题标题】:Ninject Singleton for MVC Data RepositoryNinject Singleton 用于 MVC 数据存储库
【发布时间】:2011-04-08 20:26:12
【问题描述】:

在我的 MVC3 应用程序中,我有一个 IDataRepository 接口,我的所有控制器都引用该接口,以使它们能够访问数据层。还有一个 DataRepository 类,它为特定的数据源(在我的例子中是一个 nHydrate 派生的实体框架)实现 IDataRepository。 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 吗?

附言我很晚才意识到我不需要 DataRepositoryBase,因为它的功能可以合并到 DataRepository 中。我已经这样做了,但我仍然在似乎是一个请求中多次调用 DataRepository 的构造函数。

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

--- 更多信息 ---

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

但这也让我怀疑我是否只是设计了错误的应用程序。似乎我应该将浏览器调用时可能调用的所有操作方法分组到一个控制器中。相反,我根据它们如何适合我的应用程序的概念模型来组织操作方法。

【问题讨论】:

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


    【解决方案1】:

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

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

    您真正想要的是将InRequestScope 添加到第一个代码sn-p 中。

    【讨论】:

    • @Mark 在这种情况下,您很可能在请求之外进行解析。或者您正在使用 Ninject 的多个实例,只要范围对象相同,Ninject 就会返回相同的实例。请求范围使用 HttpCONtext.Current 作为范围。检查它是否不为空,并验证您使用的是同一个 ninject 实例。
    • 我在原帖中添加了一些额外的信息,希望它可以澄清我的问题。但我不确定如何验证所有构造函数调用中是否使用了相同的 ninject 实例。这是一个静态类,我不确定实例“存储”在哪里。 HttpContext.Current 在我正在监视的构造函数调用中不为空。
    • 我已将此标记为答案,因为它是:)。我的主要问题是我认为每个返回服务器的 POST 或 GET 都是一个请求。实际上,例如,如果您将控制权从一个控制器移交给另一个控制器,或者如果您重定向到 https 或从 https 重定向,则每个请求都可以生成多个请求。这两件事我都在我的应用程序中做:)。
    【解决方案2】:

    单例还不够吗?

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

    RequestScope 不是单例,这意味着对象对于每个用户的调用都是分开的。

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

    【讨论】:

    • 你说得对,我的术语很草率。我想要做的是在一个 Web 请求的整个处理过程中使用一个 DataRepository 实例。这就是我认为 InRequestScope() 所做的。但是我可以看到在一个请求处理周期中构建了多个 DataRepository 实例。至少,我认为这是一个请求处理周期:处理单个请求以浏览到 MVC 应用程序中的不同网页。
    猜你喜欢
    • 1970-01-01
    • 2019-11-21
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    • 1970-01-01
    • 2016-02-05
    相关资源
    最近更新 更多