Unity和Simple Injector之间的IoC注册差异

时间:2013-01-31 17:23:31

标签: c# .net dependency-injection inversion-of-control simple-injector

我有一个项目使用Unity完美运行。我尝试切换到使用Simple Injector,现在没有任何更改保存在我的数据库中。我认为这与注册组件的生命周期有关。这是Unity容器注册:

private IUnityContainer GetUnityContainer()
{
    IUnityContainer container = new UnityContainer()
        .RegisterType<IDatabaseFactory, DatabaseFactory>(
            new HttpContextLifetimeManager<IDatabaseFactory>())
    .RegisterType<IUnitOfWork, UnitOfWork>(
        new HttpContextLifetimeManager<IUnitOfWork>())
    .RegisterType<ICategoryRepository, CategoryRepository>(
        new HttpContextLifetimeManager<ICategoryRepository>())
    .RegisterType<ICategoryService, CategoryService>(
        new HttpContextLifetimeManager<ICategoryService>());

    return container;         
}

这是新的Simple Injector注册。

container.Register<IDatabaseFactory, DatabaseFactory>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Register<ICategoryRepository, CategoryRepository>();
container.Register<ICategoryService, CategoryService>();

我不确定HttpContextLifetimeManager如何与Simple Injector发挥作用。 MVC是统一示例的客户端,但我正在改为WPF项目和Simple Injector。任何建议都非常感谢。感谢。


@Steven。谢谢你的评论。我刚刚发现,因为我的RepositoryBase和我的UnitOfWork在其构造函数中注入了一个IDatabaseFactory,我需要使用container.RegisterSingle<IDatabaseFactory, DatabaseFactory>()。这解决了一个问题。我的生命仍然有问题。由于我的消费应用程序是WPF,RegisterPerWebRequest将如何工作?

我的项目有一个DataLayer&gt;&gt; BusinessLayer&gt;&gt; WcfService&gt;&gt; WPF前端。简单的Injector在WcfService项目上设置,业务层有Boostrapper在那里注册项目。截至目前,我的WPF客户端将GetAllCountries()并显示在网格中。如果我更改了一个名称并尝试更新,我会得到“ObjectStateManager中已存在具有相同键的对象.ObjectStateManager无法跟踪具有相同键的多个对象。”错误。我做了一些调试,发现在WPF客户端中调用GetCountries服务之后,当我回去尝试更新时,我看到所有国家都通过dbContext.ChangeTracker.Entries()附加到上下文。此时我应该没有跟踪任何实体,因为我的上下文应该在第一个工作单元之后被处理掉。

在MVC应用程序中,RegisterPerWebRequest修复了这个问题,但WPF的等价物是什么?我现在要安装扩展程序并尝试它但我觉得这不是我正在寻找的解决方案......或者是它?再次感谢您的帮助。


行。我做了一些挖掘,找到了一个有效的解决方案。我只是不确定它是不是正确的。无论如何,现在在我的BLL中有一个注册东西的引导程序,我可以这样注册:

container.RegisterPerWcfOperation<IDatabaseFactory, DatabaseFactory>();
container.RegisterPerWcfOperation<IUnitOfWork, UnitOfWork>();
container.RegisterPerWcfOperation<ICountryRepository, CountryRepository>();

这给了我正在寻找的东西。只创建了一个DatabaseFactory实例,因此我的存储库和工作单元就像它们应该的那样共享它。此外,在客户端上的GetCountries()之后,当我第二次调用服务执行和更新时,我检查dbContext.ChangeTracker.Entries()并查看没有跟踪的实体,这是正确的。我现在可以附加,设置修改,并调用SaveChanges而不会出现重复键错误。这看起来好吗?感谢。

1 个答案:

答案 0 :(得分:6)

使用 transient 生活方式(这意味着没有缓存)的Simple Injector寄存器类型的Register重载。每次请求实例(或注入实例)时,都会创建一个新实例。在Unity中,这是相同的;默认的生活方式是 transient

似乎使用 Per Web Request 生活方式注册这些类型非常重要。当在IUnitOfWork上执行提交的类获得与实际对IUnitOfWork进行更改的类不同的实例时,更改未提交到数据库并不奇怪。

简单注射器相当于Unity的HttpContextLifetimeManagerWebRequestLifestyle。这种生活方式不是核心库的一部分,但可以使用as NuGet package

在项目中包含此项后,您可以进行以下注册:

container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

container.Register<IDatabaseFactory, DatabaseFactory>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
container.Register<ICategoryRepository, CategoryRepository>(Lifestyle.Scoped);
container.Register<ICategoryService, CategoryService>(Lifestyle.Scoped);

或同等的:

Lifestyle lifestyle = new WebRequestLifestyle();

container.Register<IDatabaseFactory, DatabaseFactory>(lifestyle);
container.Register<IUnitOfWork, UnitOfWork>(lifestyle);
container.Register<ICategoryRepository, CategoryRepository>(lifestyle);
container.Register<ICategoryService, CategoryService>(lifestyle);

WebRequestLifestyle的默认行为是在Web请求结束时处置创建的实例。无需特殊注册(Simple Injector在应用程序启动时为您挂起HttpModule。)

<小时/> UPDATE:

我很抱歉没有把你的问题读到最后一行。我错过了你想使用WPF客户端配置它的事实。

您可能知道,由于您的客户端是与WCF服务不同的应用程序,因此您的系统中将有两个Composition Roots;一个用于客户端,一个用于服务。他们的注册可能会大不相同。从Simple Injector v4.1开始,对于a WCF service,您确实需要AsyncScopedLifestyle,或者当您在dotnetjunkie/solidservices关注参考架构时,您会发现它很容易使用{{ 3}}并在两个Execute方法中明确定义范围。

我发现在两层应用程序(客户端 - >数据库)的客户端中管理对象的生命周期相当困难,因为很难为某个范围定义工作单元。由于您使用的是命令/处理程序+查询/处理程序方法,因此事情将变得如此简单。客户端不会有任何工作单元。就在服务器上。您的演示者可以依赖于几个IQueryHandler<TQuery, TResult>ICommandHandler<TCommand>接口,您就完成了。查询不会更改状态,命令应该是原子操作。换句话说,只需要在执行命令的边界内使用工作单元。