1

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

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

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

存储库实现将被注入!

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

static Manager _me = new Manager();

[Dependency]
public IRepository Repo;

注意:这是我目前进行解析的方式!我需要对此的反馈!

在管理器中,我解决了依赖关系

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

Manager 的方法如下所示:

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?
}

So, to summarize my question:

  1. Is it a bad idea to use a singleton reference (not only to a container, but at all?) in the way shown above?
  2. Am I doing the resolving right? Or should I have used BuildUp somewhere? Should I have called Resolve from the startup projects code?

Thank you for your time!

4

1 回答 1

2

Dependencies should be resolved in cascade down from the top layer classes, not using static or singleton container in constructors.

Check this link.

If your app does not provide any hook into the pipeline to resolve the dependencies (as Unity.Mvc3 does with controllers) the best aproach is resolve the Manager (your top layer class) class through Unity (you must register it first) and let the DI container inject IRepository. This alows you to keep the static/singleton container in one place and keep things under control. No other layer in your app should know anything about DI container.

An example of resolving complete dependency graph could be the next piece of code:

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

With the prorper configuration of Unity in XML or runtime I just need to resolve ClasificationManagement and Unity do the dirty work of resolving all dependecy chain.

//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")

For Unity config I like xml configuration because you can change the dependencies and no compilantion is needed. Just include this function somewhere in the initialization logic of your app.

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

A XML config should looks like:

<?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>

I hope this example hepls you to understand the phylosophy of DI. Even when I use a static container (ServiceLocator); the container is used just to load top level layer classes to avoid servicelocator antipattern.

于 2013-03-04T13:47:07.933 回答