【问题标题】:Configuring 'deep' dependencies with Unity IoC使用 Unity IoC 配置“深度”依赖项
【发布时间】:2011-10-04 12:32:13
【问题描述】:

假设我的 MVC 2 项目中有以下类和接口:

存储库:

IRepository1、IRepository2、IRepository3

public class ConcreteRepository1 : IRepository1
{
     public ConcreteRepository1()
     {
         ...
     }
     ...
}

public class ConcreteRepository2 : IRepository2
{
     public ConcreteRepository2()
     {
         ...
     }
     ...
}

public class ConcreteRepository3 : IRepository3
{
     public ConcreteRepository3()
     {
         ...
     }
     ...
}

服务类:

public class Service1
{
    private IRepository1 repo1;
    private IRepository2 repo2;

    public Service1(IRepository1 repo1, IRepository2 repo2)
    {
        this.repo1 = repo1;
        this.repo2 = repo2;
    }
    ...
}

控制器:

public class Controller1 : Controller
{
    private Service1 srv1;
    private Service2 srv2;

    public Controller1(Service1 srv1, Service2 srv2)
    {
        this.srv1 = srv1;
        this.srv2 = srv2;
    }
    ...
}

我有自定义的 ControllerFactory,并且我知道如何将具体的存储库绑定到接口:

IUnityContainer container = new UnityContainer();
container.RegisterType<IRepository1, ConcreteRepository1>(new TransientLifetimeManager(), new InjectionConstructor());
container.RegisterType<IRepository2, ConcreteRepository2>(new TransientLifetimeManager(), new InjectionConstructor());
container.RegisterType<IRepository3, ConcreteRepository3>(new TransientLifetimeManager(), new InjectionConstructor());

问题是我应该如何在我的自定义 ControllerFactory 中注册服务的实例和控制器的类型,以使统一容器解析整个层次结构 Controller->Service->Repository 并避免在控制器或服务中调用 Resolve?

谢谢。

【问题讨论】:

  • 为什么你有多个存储库?您是否访问不同的数据源?只是好奇...
  • @Yves M.:我的域层中的每个聚合根都有一个存储库。我有一个数据源,但假设这种方法支持每个聚合根位于它自己的数据源上。

标签: c# .net asp.net-mvc asp.net-mvc-2 inversion-of-control


【解决方案1】:

如果你已经注册了IRepository1-3,那么你只需调用就可以得到Service1实例

container.Resolve<Service1>()

调用container.Resolve&lt;Controller1&gt;() 将自动解决依赖关系并创建Controller1 类型的实例。

示例:

public interface IRepository1 { }
public interface IRepository2 { }
public interface IRepository3 { }

public class ConcreteRepository1 : IRepository1 { }
public class ConcreteRepository2 : IRepository2 { }
public class ConcreteRepository3 : IRepository3 { }

public class Service1
{
    private IRepository1 repo1;
    private IRepository2 repo2;

    public Service1(IRepository1 repo1, IRepository2 repo2)
    {
        this.repo1 = repo1;
        this.repo2 = repo2;
    }
}

public class Service2
{
    private IRepository1 repo1;
    private IRepository2 repo2;

    public Service2(IRepository1 repo1, IRepository3 repo3)
    {
        this.repo1 = repo1;
        this.repo2 = repo2;
    }
}

public class Controller1
{
    private Service1 srv1;
    private Service2 srv2;

    public Controller1(Service1 srv1, Service2 srv2)
    {
        this.srv1 = srv1;
        this.srv2 = srv2;
    }
}

解决:

var container = new UnityContainer();
container.RegisterType<IRepository1, ConcreteRepository1>();
container.RegisterType<IRepository2, ConcreteRepository2>();
container.RegisterType<IRepository3, ConcreteRepository3>();

var controller = container.Resolve<Controller1>();

编辑

public interface IRepository { }
public class Repository : IRepository { }

public class Service
{
    //[InjectionConstructor]
    public Service()
    {
        Console.WriteLine("Parameterless constructor called");
    }

    public Service(IRepository repository)
    {
        Console.WriteLine("Contructor with IRepository called");
    }
}

private static void Main()
{
    var container = new UnityContainer();
    container.RegisterType<IRepository, Repository>();
    var service = container.Resolve<Service>();
    container.RegisterType<Service>(new InjectionConstructor());
    var service2 = container.Resolve<Service>();
}

输出:

Contructor with IRepository called
Parameterless constructor called

所以,当我们没有注册Service(换句话说,它具有默认解析行为)时,Unity默认使用最贪婪的构造函数构造Service。当您指定 new InjectionConstructor() 时,这会告诉 Unity 使用无参数构造函数。如果您将构造函数(在本例中为 public Service())标记为 InjectionConstructorAttribute,则会收到相同的行为。

【讨论】:

  • 我明白了,谢谢。我试图用下面的代码注册所有控制器的类型,当我删除它时一切正常:var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes() where typeof(IController).IsAssignableFrom(t) select t; foreach (Type t in controllerTypes) { container.RegisterType(t, new TransientLifetimeManager(), new InjectionConstructor()); }
  • 所以看起来在这种情况下所有服务/控制器类型都会自动注册到 Unity,对吧?有没有办法可以禁用此“自动注册”并手动逐个或全部注册每种类型/实例?
  • @Intruder,当然,您可以,无需设置任何“禁用自动解析”选项。你发现了什么异常?
  • 当我使用我对您的答案的第一条评论中提供的代码手动注册控制器时,我得到“ 没有采用参数 () 的构造函数。来源:Microsoft.Practices.Unity”异常
  • @Intruder,那是因为你传递 new InjectionConstructor() 没有参数,因此 Unity 尝试使用无参数构造函数解析 Controller 类,正如我所见,你的 Controller 构造函数有 2 个参数。自己注册类型的主要目的是什么?
【解决方案2】:

当然就是以下-

container.RegisterType<Service1>(new TransientLifetimeManager(), new InjectionConstructor());

Service2 也是如此。 IoC 容器将为您构建对象

【讨论】:

    猜你喜欢
    • 2017-07-15
    • 1970-01-01
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多