Windows services 使用Ninject和Windows服务的InSingletonScope

Windows services 使用Ninject和Windows服务的InSingletonScope,windows-services,entity-framework-4.1,ef-code-first,ninject,Windows Services,Entity Framework 4.1,Ef Code First,Ninject,我重新发布了这个问题,因为我觉得它有点模糊 我目前正在使用一个2分钟计时器的Windows服务。我首先使用EF代码和用于数据访问的存储库模式。我正在使用Ninject注入依赖项。我的NinjectDependencyResolver类中有以下绑定: ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["Database"]; Bind<IDatabaseFac

我重新发布了这个问题,因为我觉得它有点模糊

我目前正在使用一个2分钟计时器的Windows服务。我首先使用EF代码和用于数据访问的存储库模式。我正在使用Ninject注入依赖项。我的NinjectDependencyResolver类中有以下绑定:

ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["Database"];

Bind<IDatabaseFactory>().To<DatabaseFactory>()
                        .InSingletonScope()
                        .WithConstructorArgument("connectionString", connectionStringSettings.Name);

Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope();
Bind<IMyRepository>().To<MyRepository>().InSingletonScope();
我开始在我的日志中看到一个错误,上面写着:

已成功提交对数据库的更改,但更新对象上下文时出错。ObjectContext可能处于不一致的状态。内部异常消息:AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突。在调用AcceptChanges之前,请确保键值是唯一的


在Windows服务中使用Ninject时使用InSingeltonScope正确吗?我相信我尝试过使用不同的作用域,比如InTransientScope,但我只能让InSingeltonScope处理数据访问。错误消息与作用域有关还是无关?

InSingletonScope
将在整个服务生命周期内创建singleton上下文=一个上下文。它是。因为上下文保存了所有以前时间事件中的所有对象,所以它的内存消耗会增加,并且可能会出现与当前接收到的错误相同的错误(但是错误确实可能与您的单例上下文无关,但很可能不是)。例外情况是,上下文跟踪两个具有相同密钥标识符的不同对象,这是不允许的


存储库和上下文不使用单例uow,而是使用单例工厂,每次甚至都从工厂请求新的实例。在事件处理结束时处置上下文

InSingletonScope
将为整个服务生命周期创建一个上下文。它是。因为上下文保存了所有以前时间事件中的所有对象,所以它的内存消耗会增加,并且可能会出现与当前接收到的错误相同的错误(但是错误确实可能与您的单例上下文无关,但很可能不是)。例外情况是,上下文跟踪两个具有相同密钥标识符的不同对象,这是不允许的


存储库和上下文不使用单例uow,而是使用单例工厂,每次甚至都从工厂请求新的实例。在事件处理结束时处置上下文

假设服务不是在数据库上运行的唯一进程,则不应使用Singleton。本例中发生的情况是,您正在重用一个DBContext,该DBContext具有过时的缓存实体

更好的方法是以类似于web/wcf请求的方式处理服务的每个计时器执行,并为请求创建一个新的作业处理器

var processor = factory.CreateRowsProcessor();
processor.ProcessRows(rows);

public class RowsProcessor
{
    public Processor(UoW uow, ....)
    {
        ...
    }

    public void ProcessRows(Rows[] rows)
    {
        foreach (var row in rows)
        {
            var existing = myRepository.GetById(row.Id);

            if (existing == null)
            {
                existing = new Row();
                myRepository.Add(existing);

                unitOfWork.Commit();
            }
        }
    }
}
根据问题的不同,最好将循环放在外部,并为每一行使用一个新的处理器


有关工厂的更多信息,请阅读。如果需要将UoW注入多个类,还可以查看命名范围扩展的InCallScope

假设服务不是在数据库上运行的唯一进程,则不应使用Singleton。本例中发生的情况是,您正在重用一个DBContext,该DBContext具有过时的缓存实体

更好的方法是以类似于web/wcf请求的方式处理服务的每个计时器执行,并为请求创建一个新的作业处理器

var processor = factory.CreateRowsProcessor();
processor.ProcessRows(rows);

public class RowsProcessor
{
    public Processor(UoW uow, ....)
    {
        ...
    }

    public void ProcessRows(Rows[] rows)
    {
        foreach (var row in rows)
        {
            var existing = myRepository.GetById(row.Id);

            if (existing == null)
            {
                existing = new Row();
                myRepository.Add(existing);

                unitOfWork.Commit();
            }
        }
    }
}
根据问题的不同,最好将循环放在外部,并为每一行使用一个新的处理器


有关工厂的更多信息,请阅读。如果需要将UoW注入多个类,还可以查看命名范围扩展的InCallScope

拉迪斯拉夫,你能指出一些代码示例吗?我对如何设置带有绑定的单例工厂有点迷茫,因为每次使用工厂时都会创建对象的新实例。非常感谢您的帮助。工厂只需调用对象的构造函数。并非所有的东西都需要注射。工厂的重点是要知道如何创建特定类型的实例。Ladislav,我用一个更清晰的描述重新提出了这个问题,我试图做什么。拉迪斯拉夫,你能指出一些代码示例吗?我对如何设置带有绑定的单例工厂有点迷茫,因为每次使用工厂时都会创建对象的新实例。非常感谢您的帮助。工厂只需调用对象的构造函数。并非所有的东西都需要注射。工厂的重点是要知道如何创建特定类型的实例。Ladislav,我用一个更清晰的描述重新提出了这个问题,我试图做什么。Remo,我读了你关于ninject工厂的文章,但这似乎是ninject 3.0的一部分?我目前正在使用2.2.1.4。还有其他文章我可以看吗?当我选择将Ninject与windows服务结合使用时,我似乎有些不知所措。感谢您的帮助。我建议您更新。这应该是可能的,没有任何巨大的变化。否则,您必须手动实现工厂,但其他任何操作都保持不变。我将研究Ninject 3作为一个选项。谢谢。雷莫,我读了你关于ninject工厂的文章,但这似乎是ninject 3.0的一部分?我目前正在使用2.2.1.4。还有其他文章我可以看吗?当我选择将Ninject与windows服务结合使用时,我似乎有些不知所措。感谢您的帮助。我建议您更新。这应该是可能的,没有任何巨大的变化。否则,您必须手动实现工厂,但其他任何操作都保持不变。我将研究Ninject 3作为一个选项。谢谢