Unity 和简单注入器之间的 IoC 注册差异

本文关键字:IoC 注册 之间 简单 注入器 Unity | 更新日期: 2023-09-27 17:56:47

我有一个使用 Unity 运行良好的项目。我尝试切换到使用简单注射器,现在没有更改保存在我的数据库中。我相信这与注册组件的寿命有关。以下是 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;         
}

这是新的简单注射器注册。

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

我不确定HttpContextLifetimeManager是如何与简单注射器一起发挥作用的。MVC 是 Unity 示例的客户端,但我正在更改为 WPF 项目和简单注入器。任何建议都非常感谢。谢谢。


@Steven。感谢您的评论。我刚刚发现,由于我的存储库库和我的工作单元在它们的构造函数中注入了一个 IDatabaseFactory,我需要使用 container.RegisterSingle<IDatabaseFactory, DatabaseFactory>() .这解决了一个问题。不过,我仍然有终身问题。由于我的使用应用程序是 WPF,因此 RegisterPerWebRequest 将如何工作?

我的项目有一个数据层>>业务层>> WcfService>> WPF 前端。Simple Injector设置在WcfService项目上,业务层有Boostrapper来注册那里的项目。截至目前,我的 WPF 客户端将 GetAllCountry() 并显示在网格中。如果我更改一个名称并尝试更新,我会得到"ObjectStateManager 中已存在具有相同键的对象。对象状态管理器无法跟踪具有相同键的多个对象"错误。我已经做了一些调试,发现在 WPF 客户端中的 GetStates 服务调用之后,当我返回尝试更新时,我看到所有国家/地区都通过 dbContext.ChangeTracker.Entries() 附加到上下文。在这一点上,我应该没有被跟踪的实体,因为我的上下文应该在第一个工作单元之后被处理掉。

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


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

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

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

Unity 和简单注入器之间的 IoC 注册差异

Register使用

瞬态生活方式(这意味着没有缓存)对简单注入器寄存器类型进行重载。每次请求实例(或注入实例)时,都会创建一个新实例。在 Unity 中,这是相同的;默认的生活方式是短暂的

似乎使用每 Web 请求生活方式注册这些类型非常重要。当在IUnitOfWork上执行这些提交的类获得与实际对IUnitOfWork进行更改的类不同的实例时,更改不会提交到数据库也就不足为奇了。

Simple Injector相当于Unity的HttpContextLifetimeManager是WebRequestLifestyle。此生活方式不是核心库的一部分,但以 NuGet 包的形式提供。

将其包含在项目中后,可以执行以下注册:

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 请求结束时释放创建的实例。不需要特殊注册(简单注射器在应用程序启动时为您连接HttpModule)。


更新:

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

您可能知道,由于客户端是与 WCF 服务不同的应用程序,因此系统中将有两个组合根:一个用于客户端,一个用于服务。他们的注册可能会大不相同。从Simple Injector v4.1开始,对于WCF服务,您确实需要一个AsyncScopedLifestyle,或者当您遵循dotnetjunkie/solidservices的参考体系结构时,您会发现使用ThreadScopedLifestyle并在两个Execute方法中显式定义范围一样简单。

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