【问题标题】:Dependency Injection - How to inject implementation of interface using Simple Injector when the implementation uses Unity for DI依赖注入 - 当实现使用 Unity for DI 时,如何使用 Simple Injector 注入接口实现
【发布时间】:2016-06-10 18:30:39
【问题描述】:

我有两个独立的项目...一个项目使用 Simple Injector,另一个项目使用 Unity。从简单的注入器项目中,我尝试使用 Unity 为其 DI 注册位于项目中的类的接口/实现。我可以成功地做到这一点并获得对该类的访问权限,但是该类中标记为 Unity [Dependency] 的任何内容都无法解决。我可以将这些依赖项注册到 Simple Injector 容器,但一旦使用 Unity 进入类,它就会丢失。

例子:

Project1(使用简单注入器)

public class StartUp {
    var container = new Container();
    container.RegisterSingleton(typeof(IGenericRepo<>), typeof(GenericRepo));
    container.RegisterSingleton<IService, Service>();
    //more code below etc...
}

public class TestController
{
    private readonly IService service;

    public TestController(IService service)
    {
        this.service = service;
    }

    public void TestMethod()
    {
        var test = service.GetEverything();
    }
}

Project2(使用 Unity)

public class Service : IService
{
    [Dependency]
    public IGenericRepo<ServiceObj> _serviceRepo { private get; set; }

    public IQueryable<ServiceObj> GetEverything()
    {
        return _serviceRepo.Get();
    }
}

通过上面的示例,我可以访问项目 2 中的 GetEverything 方法,但是 _serviceRepo 依赖项为空。有没有办法让它知道使用 Project1 中注册的 GenericRepo?

这样可以吗?

谢谢! 瑞恩

【问题讨论】:

  • 你在哪里注册你的 serviceRepo 在项目二?见:msdn.microsoft.com/en-us/library/dn178463(v=pandp.30).aspx
  • Project2 目前没有明确注册任何东西......到目前为止,唯一使用它的其他项目是其他 Unity 项目,其中注册是在 web.config 中完成的,或者在应用程序。
  • 您可以将第一个项目的 dll 包含在第二个项目的引用中,然后注册它。
  • Project1其实是一个web服务(web api)
  • 你真的不应该在你的类库中使用 DI 容器。看看这篇文章:blog.ploeh.dk/2011/07/28/CompositionRoot

标签: c# dependency-injection unity-container simple-injector


【解决方案1】:

如果我理解正确,项目 2 是一些共享项目,用于其他使用 Unity 进行依赖注入的项目。在这种情况下,Unity 通过使用 DependencyAttribute 注释属性来使用属性注入。

Simple Injector 能够进行属性注入。然而,属性注入应该只用于可选依赖项。当您遇到NullReferenceException 时,此依赖项不是可选的!

所以你应该将IGenericRepo&lt;ServiceObj&gt; 移动到IService 的构造函数中。这让IService 的用户清楚地知道它需要一个存储库才能正常运行。当您对IService 进行单元测试时,这变得特别有用,因为在这种情况下,构造函数会清楚地传达它需要一个存储库。

通过将依赖项移动到构造函数中,Simple Injector 将正确注入存储库,如果配置无效,则抛出 ActivationException

您可以通过调用container.Verify() 进行测试,我建议您这样做:Verify the container’s configuration。这将使申请成为fail fast

如果项目 2 无法重构或由于其他令人信服的原因无法选择构造函数注入,Simple Injector 确实支持属性注入。但是,它不支持这种开箱即用的方式。 Simple Injector 的设计原则之一是to never fail silently,因此只建议使用Explicit property injection。这将使容器有机会使用其Diagnostic Services,如果配置无效,则快速失败。

正如您在参考文档中所读到的,有两种方法可以进行属性注入:

  1. 通过注册初始化程序并调用 container.RegisterInitializer()
  2. 通过实现IPropertySelectionBehavior

选项 2 将让 Simple Injector 使用 Diagnostics Services 自动检查依赖关系。在验证所有“初始化程序”时也会执行,但不会检查 lambda 中的代码的生活方式等。

Simple Injector 不鼓励其用户依赖容器,因此它不包含任何您可以直接使用的 Atrributes,例如 Unity 有 DependencyAttribute

所以你有两个选择:

  1. 让项目 1 也依赖于 Unity(它间接已经拥有它!,糟糕)并创建 IPropertySelectionBehavior 的实现以搜索 Unity DependencyAttribute
  2. 在项目 2 中创建您自己的自定义 Attribute 并注释此自定义属性的 _serviceRepo

1 和 2 之间的唯一区别是搜索的属性。 如果您无法触摸项目 2,则选项 2 是不可能的。实现IPropertySelectionBehavior 很简单:

// custom attribute only for option 1
public class ImportAttribute : Attribute { }

class UnityDependencyPropertySelectionBehavior : IPropertySelectionBehavior 
{
     public bool SelectProperty(Type type, PropertyInfo prop) 
     {
         return prop.GetCustomAttributes(typeof(DependencyAttribute)).Any();
     }
}

您可以通过以下方式使用此自定义 IPropertySelectionBehavior 配置容器:

container.Options.PropertySelectionBehavior = 
               new UnityDependencyPropertySelectionBehavior();

总结一下: 将依赖项移至构造函数,因为它不是可选依赖项。换句话说,使用构造函数注入! 如果有令人信服的理由不这样做,请实施IPropertySelectionBehavior

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    相关资源
    最近更新 更多