依赖注入:我应该在哪里注射?谁应该控制它?

时间:2013-02-25 10:22:01

标签: c# dependency-injection inversion-of-control unity-container

免责声明:没有编译器编写的代码,您应该丢弃任何语法错误。 :)

我想知道我在做什么是“正确的”。

目前,我有一个带有静态方法的Manager类。这些方法都在我的Repository类上调用一个方法(例如,Manager.Get将调用Repository.Get,依此类推)。

将注入Repository实现!

Manager有一个静态字段,它引用单例实例到自身,以及对存储库实例的引用。

static Manager _me = new Manager();

[Dependency]
public IRepository Repo;

注意:这就是我目前的解决方法!我需要对此提出反馈意见!

在经理Ctor中,我解决了依赖

public Manager()
{
    // Feedback would be nice on this as well!
    // I have a singleton reference to the container,
    // being set from the startup project.
    Repo = Singleton.UnityContainer.Resolve<IRepository>();
}

经理的方法如下:

public static MyObject Get(int id)
{
    return _me.Repo.Get(id);
}

在我的主程序(例如控制台应用程序)中,我将注册我的实现。

static void Main(string[] args)
{
    var container = Singleton.UnityContainer = new UnityContainer();
    // The implementation to inject, could change over time
    // to a MSSQL or MySQL, who knows? Hence the DI!
    var myXmlRepo = new XmlRepository("C:\My.xml");
    // Register the instance
    container.RegisterInstance(myXmlRepo);
    container.RegisterInstance<IRepository>(myXmlRepo, new ContainerControlledLifetimeManager()); // Why do I need to register TWICE?
}

所以,总结一下我的问题:

  1. 以上面显示的方式使用单例引用(不仅仅是容器,而是根本?)是不是一个坏主意?
  2. 我在做解决吗?或者我应该在某处使用BuildUp?我应该从启动项目代码中调用Resolve吗?
  3. 感谢您的时间!

1 个答案:

答案 0 :(得分:2)

依赖关系应该从顶层类向下级联,而不是在构造函数中使用静态或单例容器。

选中link

如果你的应用程序没有提供任何钩子进入管道以解决依赖关系(如Unity.Mvc3对控制器那样),最好的方法是通过Unity解析Manager(你的顶层类)类(你必须先注册)并让DI容器注入IRepository。这使得您可以将静态/单件容器保存在一个位置并控制事物。您的应用中没有其他图层可以了解有关DI容器的任何信息。

解析完整依赖图的一个例子可能是下一段代码:

Public Class ClasificationManagement //application layer service, top layer class
    Implements IClasificationManagement

    Private _servicio As IClasificacionesService //inject domain serice for bussines
    Private _repositorio As IClasificationRepository //inject repository for perisitence

    Public Sub New(ByVal servicio As IClasificacionesService, ByVal repositorio As IClasificationRepository)
        _servicio = servicio
        _repositorio = repositorio
    End Sub

    Public sub SwapDescrition(ByVal clasificationOrigenID As String, ByVal clasificationDestinoID As String) Implements IClasificationManagement. SwapDescrition

        //code using domain services and repositories

    End sub

Public class ClasificacionesService
    implements IClasificacionesService

  private _tracer as ITracer //inject tracer to service domain

  public sub new(tracer as ITracer)
    _tracer =  tracer
  end sub

  //not relevant code using ITracer

End Class

通过在XML或运行时使用Unity的prorper配置,我只需要解决ClasificationManagement,Unity就可以完成解决所有依赖链的肮脏工作。

//resolve manager
    manager = ServiceLocator.Current.GetInstance(Of IClasificationManager)()
//use manager, all dependencies (bussines service, repositories, tracers) were injected by Unity
    manager.SwapDescrition("123-ABC", "456-DEF")

对于Unity配置,我喜欢xml配置,因为您可以更改依赖关系,不需要进行任何编译。只需在应用程序的初始化逻辑中的某处包含此功能。

Imports Microsoft.Practices.Unity
Imports Microsoft.Practices.Unity.Configuration
Imports Microsoft.Practices.ServiceLocation
    Private Sub InitServiceLocator()
        Dim container As IUnityContainer = New UnityContainer()
        container.LoadConfiguration() //read xml config
         //container.RegisterType<Of ...>(...) //config in runtime
        Dim provider = New UnityServiceLocator(container)
        ServiceLocator.SetLocatorProvider(Function() provider)
    End Sub

XML配置应如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">

    <alias alias="IClasificationManagement" type="AppPrincipal.IClasificationManagement, AppPrincipal" />
    <alias alias="IClasificationRepository" type="X509ValDAL.IClasificationRepository, X509ValDAL" />
    <alias alias="IClasificacionesService" type="Entidades.IClasificacionesService, Entidades" />
    <alias alias="IUnitOfWork" type="X509ValDAL.IUnitOfWork, X509ValDAL" />
    <alias alias="ObjectContext" type="System.Data.Objects.ObjectContext, System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <alias alias="ClasificationManagement" type="AppPrincipal.ClasificationManagement, AppPrincipal" />
    <alias alias="ClasificationRepository" type="X509ValDAL.ClasificationRepository, X509ValDAL" />
    <alias alias="ClasificacionesService" type="Entidades.ClasificacionesService, Entidades" />
    <alias alias="UnitOfWork" type="X509ValDAL.UnitOfWork, X509ValDAL" />
    <alias alias="X509VALEntities" type="Entidades.X509VALEntities, Entidades" />


    <assembly name="AppPrincipal" />
    <assembly name="X509ValDAL" />
    <assembly name="Entidades" />
    <assembly name="System.Data.Entity" />

    <namespace name="AppPrincipal" />
    <namespace name="X509ValDAL" />
    <namespace name="Entidades" />
    <namespace name="System.Data.Objects" />
    <container>

        <register type="IClasificationManagement" mapTo="ClasificationManagement">
            <constructor>
                <param name="servicio">
                    <dependency/>
                </param>
                <param name="repositorio">
                    <dependency/>
                </param>
            </constructor>
        </register>
    <register type="IClasificationRepository" mapTo="ClasificationRepository">
            <constructor>
                <param name="uow">
                    <dependency/>
                </param>
            </constructor>
        </register>

        <register type="IClasificacionesService" mapTo="ClasificacionesService" />
                 TODO: Inject ITracer

        <register type="ObjectContext" mapTo="X509VALEntities" />

        <register type="IUnitOfWork" mapTo="UnitOfWork" >
            <constructor>
                <param name="context">
                    <dependency />
                </param>
            </constructor>
        </register>     

    </container>
</unity>

我希望这个例子能让你理解DI的哲学。即使我使用静态容器(ServiceLocator);容器仅用于加载顶级层类以避免servicelocator反模式。