依赖注入 - 当实现使用Unity for DI时,如何使用Simple Injector注入接口的实现

时间:2016-06-10 18:30:40

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

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

示例:

Project1 (使用Simple Injector)

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();
    }
}

通过上面的示例,我可以在Project 2中找到GetEverything方法,但是_serviceRepo依赖性为null。有没有办法让它知道使用注册的GenericRepo&lt;&gt;来自Project1?

这可能吗?

谢谢! 莱恩

1 个答案:

答案 0 :(得分:1)

如果我理解正确,Project 2是一些共享项目,在其他使用Unity for Dependency Injection的项目中使用。在这种情况下,Unity通过使用DependencyAttribute注释属性来使用属性注入。

Simple Injector能够进行属性注入。但是,属性注入只应用于可选的依赖项。当你遇到NullReferenceException时,这种依赖不是可选的!

所以你应该将IGenericRepo<ServiceObj>移动到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
  3. 选项2将允许Simple Injector自动使用Diagnostics Services检查依赖项。验证所有'初始化程序'时也会执行,但不检查lambda中的代码的生活方式等。

    Simple Injector不鼓励其用户依赖容器,因此它不包含任何可以开箱即用的Atrributes,例如Unity具有DependencyAttribute

    所以你有两个选择:

    1. 让项目1也依赖于Unity(它间接已经拥有!,yuck)并创建IPropertySelectionBehavior的实现来搜索Unity DependencyAttribute
    2. 在项目2中创建您自己的自定义Attribute,并注释此自定义属性的_serviceRepo
    3. 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