InSingletonScope使用Ninject和Windows服务

时间:2012-02-08 22:03:02

标签: windows-services entity-framework-4.1 ef-code-first ninject

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

我目前正在使用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();

当我的服务每2分钟运行一次时,我做了类似的事情:

foreach (var row in rows)
{
    var existing = myRepository.GetById(row.Id);

    if (existing == null)
    {
        existing = new Row();

        myRepository.Add(existing);

        unitOfWork.Commit();
    }
}

我开始在日志中看到错误说:

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

在Windows服务中使用Ninject时使用InSingeltonScope是否正确?我相信我尝试使用不同的范围,如InTransientScope,但我只能使用InSingeltonScope来处理数据访问。错误消息是否与Scope有关或者它是否无关?

2 个答案:

答案 0 :(得分:3)

假设该服务不是对数据库进行操作的唯一进程,则不应使用Singleton。在这种情况下会发生的情况是,您正在重用具有过期实例的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();
            }
        }
    }
}

根据问题的不同,将循环放在外面并为每一行设置一个新的处理器可能更好。

阅读http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/以获取有关工厂的更多信息。如果需要将UoW注入多个类,还可以查看命名范围扩展的InCallScope。 http://www.planetgeek.ch/2010/12/08/how-to-use-the-additional-ninject-scopes-of-namedscope/

答案 1 :(得分:2)

InSingletonScope将为您的服务的整个生命周期创建单一上下文=一个上下文。它是very bad solution。因为上下文包含来自所有先前时间事件的所有对象,所以它的内存消耗增加,并且有可能将错误视为您当前正在接收的错误(但错误实际上可能与您的单例上下文无关,但很可能不是)。例外情况表明,您有两个不同的对象,这些对象具有由上下文跟踪的相同密钥标识符 - 这是不允许的。

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