【问题标题】:Is Ninject creating 2 separate context?Ninject 是否创建了 2 个单独的上下文?
【发布时间】:2016-03-16 23:48:03
【问题描述】:

我正在创建一个 Web API,并且我正在使用 Ninject 的依赖注入。

我有:

IRTW 存储库 模型工厂

我像这样将这 2 个注入到我的控制器中。

private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IRTWRepository>().To<RTWRepository>();
            kernel.Bind<RTWAPIContext>().To<RTWAPIContext>();          
            kernel.Bind<IModelFactory>().To<ModelFactory>();
        } 

我的 RTWRepository 构造函数如下所示

 public class RTWRepository :IRTWRepository
    {
        private RTWAPIContext _context;

        public RTWRepository(RTWAPIContext context)
        {
            _context = context;
        }}

我的 ModelFactory 构造函数如下所示

public class ModelFactory : IModelFactory
    {
        private IRTWRepository _repo;        

        public ModelFactory(IRTWRepository repo)
        {
            _repo = repo;
        } 
}

我有一个如下所示的控制器:

public MaterialsController(IRTWRepository repository,IModelFactory modelFactory) 
            : base(repository,modelFactory)
        {

        }

现在,我的问题是:Ninject 在创建我的 RTWRepository 实例以及创建 ModelFactory 实例时是否创建了 2 个单独的上下文?

我之所以问这个问题是因为当我尝试将一个依赖于另一个对象的实体保存到之前从数据库中检索到的另一个对象时遇到了问题。

我将实体保存在我的控制器中,但我在我的模型工厂中创建它以及依赖项。

public class RecycleCenter
    {
        public RecycleCenter()
        {

        }

        public int MyProperty { get; set; }


        [Required]
        public virtual Address Address { get; set; }        
    }

上面的代码是针对具有地址的实体回收中心,这个回收中心实体是在我的模型工厂中创建的,然后在我的控制器中我尝试保存它但是当我的存储库执行此行时

 _context.RecycleCenters.Add(entity);

我收到了这个错误

An entity object cannot be referenced by multiple instances of IEntityChangeTracker

所以,在我的代码中某处我使用 2 上下文而不是 1,我认为在创建 ModelFactory 和 RTWRepository 时,这个假设是否正确?如果是,我该如何解决?

【问题讨论】:

    标签: c# asp.net .net entity-framework


    【解决方案1】:

    TL;DR;

    您可能需要更改此行:

    kernel.Bind<RTWAPIContext>().To<RTWAPIContext>();    
    

    到

    kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InRequestContext();    
    

    解释:

    当您在 Ninject 中定义绑定时,您还指定了应该如何处理该对象的生命周期。

    如果你没有明确定义它,Ninject 的默认生命周期是Transient。 Transient 表示每次需要实例时,都会创建一个新实例。在您的情况下,您需要两个实例:一个用于ModelFactory 的RTWRepository,另一个用于MaterialsController 的RTWRepository。

    您可以将生活方式修改为以下选项之一:

    • 单例 ==> kernel.Bind&lt;RTWAPIContext&gt;().To&lt;RTWAPIContext&gt;().InSingleTonScope();
    • 请求 ==> kernel.Bind&lt;RTWAPIContext&gt;().To&lt;RTWAPIContext&gt;().InRequestScope();
    • 线程 ==> kernel.Bind&lt;RTWAPIContext&gt;().To&lt;RTWAPIContext&gt;().InThreadScope();
    • 命名、调用、父级、自定义

    在您的情况下,我认为您需要InRequestScope,但您必须检查必要的生命周期,因为它取决于应用程序。

    如需更多信息,请查看此处的文档:https://github.com/ninject/ninject/wiki/Object-Scopes

    【讨论】:

      【解决方案2】:

      很可能是这样。没有注释告诉 Ninject “嘿,停止,当你创建了一次实例后,重用它”。您应该同意,在大多数情况下,您需要一个对象的多个实例,而且在极少数情况下,您只需要一次。

      如果要重用实例,请使用单例模式。 Ninject 对它很熟悉,所以可以将对象映射绑定到一个方法上

      kernel.Bind<RTWAPIContext>().ToMethod(c => RTWAPIContext.GetInstance());
      

      还有一个ToSingleton 绑定,但我敢打赌,由于其他 ASP.NET 问题(例如,ASP.NET Identity 将尝试调用上下文的方法来创建对象),您不能将上下文构造函数设为私有并实现 C# 特定的单例)。

      【讨论】:

      • ToSingleton-方法与类的实现无关。您可以定义一个常规类,Ninject 只会创建一个实例然后重用它。不需要私有构造函数。
      • 感谢您的评论。我不知道。实际上,我的评论是关于 ASP.NET Identity 在ApplicationDbContext 中默认生成的Create() 方法。所以我的想法是,如果一个人真的只想要一个实例,将这种方法更改为单例方法 - 供 Ninject、开发人员和 Identity 使用
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-26
      • 2021-12-06
      相关资源
      最近更新 更多