【问题标题】:When and where todo dependency injection.Could you clarify?何时何地进行依赖注入。你能澄清一下吗?
【发布时间】:2012-01-02 10:20:07
【问题描述】:

对 DI 越来越熟悉,但我仍然有一些小问题。

阅读一些文章,上面写着“必须在入口点进行注入”

假设我有一种情况,我们有 wcf 服务,这些服务供内部 win/web 应用程序使用,而外部第三方使用这些 wcf 服务。

现在您在哪里注入服务和存储库? 以上对我来说似乎是一个常见的场景!

我还传递了所有这些接口。(非常适合模拟)我如何阻止某人从应该调用存储库的层调用 EG 我的存储库。

EG 只有业务层应该调用 DAL。 现在,通过将 IRepository 注入控制器,开发人员可以调用 DAL。

有什么建议吗?清除所有这些的链接

我的可怜人 DI 的点头示例。我如何在 entryPoint 使用 unity 和 Injecting all 来做同样的事情?

[TestFixture]
public class Class1
{
    [Test]
    public void GetAll_when_called_is_invoked()
    {
        var mockRepository = new Mock<ICustomerRepository>();
        mockRepository.Setup(x => x.GetAll()).Verifiable();

        new CustomerService(mockRepository.Object);
        ICustomerBiz customerBiz = new CustomerBizImp(mockRepository.Object);

        customerBiz.GetAll();
        mockRepository.Verify(x=>x.GetAll(),Times.AtLeastOnce());
    }
}
public class CustomerService : ICustomerService  //For brevity (in real will be a wcf service)
{
    private readonly ICustomerRepository _customerRepository;

    public CustomerService(ICustomerRepository customerRepository)
    {
        _customerRepository = customerRepository;
    }

    public IEnumerable<Customer> GetAll()
    {
        return _customerRepository.GetAll();
    }
}

public class CustomerBizImp : ICustomerBiz
{
    private readonly ICustomerRepository _customerRepository;

    public CustomerBizImp(ICustomerRepository customerRepository)
    {
        _customerRepository = customerRepository;
    }

    public IEnumerable<Customer> GetAll()
    {
        return _customerRepository.GetAll();
    }
}

public class CustomerRepository : ICustomerRepository
{
    public IEnumerable<Customer> GetAll()
    {
        throw new NotImplementedException();
    }
}
public interface ICustomerRepository
{
    IEnumerable<Customer> GetAll();
}

public interface ICustomerService
{
    IEnumerable<Customer> GetAll();
}

public interface ICustomerBiz
{
    IEnumerable<Customer> GetAll();
}

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

谢谢

【问题讨论】:

  • 我们过去只在代码中执行基于 DEBUG 的构建 DI。换句话说,生产从来没有使用过基于 DI 的代码。
  • @zenwalker 那么你已经在使用 DI 浪费了你的时间,使用它的最佳理由之一是你可以注入不同的模块进行开发、测试和发布,每个模块都单独测试。
  • 是的,这就是我的意思。我们做 DI 只是为了测试目的,即调试模式。我们没有将它们作为我们生产代码的一部分(即发布模式)发送给客户。抱歉,如果之前不清楚。

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


【解决方案1】:

这是一篇关于Composition roots 的博文,或者您所说的入口点。它来自 Dependency Injection in .NET 的作者 Mark Seemann。如果您正在寻找对 DI 的深刻理解,这本书是必读的。

有很多关于如何结合 WCF 和 DI 的示例。如果你在 IIS 中托管你的服务,你需要编写一个自定义的 ServiceHostFactory 来初始化你的 DI 容器。这是Microsoft's Unity 的示例。

至于

如何阻止某人从不应调用存储库的层调用 EG 我的存储库

您是否使用穷人的 DI 并通过所有层传递所有引用?那么您绝对应该考虑使用 DI/IoC 容器,例如 StructureMapCastle WindsorAutoFacUnity

如果您问“我一般如何避免有人不遵循我的层边界的情况”:如果程序集引用另一个它不应引用的程序集(例如 UI 不应引用 DAL),则编写失败的测试。


更新

我假设您希望服务使用 ICustomerBiz 而不是 ICustomerRepository。如果这是正确的,Unity 的设置将如下所示:

[TestMethod]
public void GetAll_with_Unity()
{
  var container = new UnityContainer();
  container.RegisterType<ICustomerRepository, CustomerRepository>();
  container.RegisterType<ICustomerBiz, CustomerBizImp>();
  container.RegisterType<ICustomerService, CustomerService>();
  var svc = container.Resolve<ICustomerService>();
  var all = svc.GetAll();
  Assert.AreEqual(1, all.Count());
}

【讨论】:

  • @Weber 感谢您的回复和链接。我已经阅读了 Mark Seeman 的帖子 + 我现在正在考虑编写 ServiceHostFactory.Poor Man 的 DI。是的,我正在这样做。是否有使用 Unity 的示例来展示如何避免传递参考?我正在做 UI --> (channelFactory)ServiceLayer(wcf) ---> BizLayer-->Dal。只有 Biz Layer 应该调用 DAL.Injecting 到构造函数(传递)IService 和 IRepository 层之间
  • TecX project 包含一个关于如何使用 Unity 注入服务的 sample。您的视图模型类需要一个带有 IMyService 参数的构造函数。然后告诉 Unity IMyService 应该使用 ChannelFactory 进行映射。在服务端,您的服务实现采用 IMyBiz 参数,业务逻辑实现采用 IDal。你需要告诉 Unity IMyBiz 映射到 MyBizImplIDalNHibernateDal 并且你完成了。
  • @Weber 感谢您的链接。消化链接。您所描述的正是我想要做的。是否有或遇到过一个从头到尾使用统一的示例,并且有兴趣查看各个项目如何相互引用等...
  • @Weber 添加了点头的实施示例。
  • @Weber 非常感谢。这帮助很大
【解决方案2】:

DI 更多的是在你的依赖架构中注入一个依赖,这就是为什么它不能解决你面临的层隔离问题。

如果需要,生产代码可以并且应该包含DI 代码。

  • 如果我们谈论的是 plugin-based architectureDI 是最自然的选择之一。

  • 如果我们谈论的是应用程序行为更改,例如Logging 系统选择:如果连接存在,则保存在远程服务器上,如果不注入本地记录器以供将来与服务器同步。

DI 在生产环境中有很多用法,但所有这一切都取决于Architect 来决定何时如何如果 em> 使用它。

换句话说,它没有单一的使用规则,它不是任何钉子的悍马,所以在认为合适的地方使用它并明智地使用它。

【讨论】:

  • 感谢您的回复。当使用依赖注入时,如何防止从不打算从层调用存储库。任何地方的示例?
  • @user231465: 域模型中的repository 是一个超类,它必须负责管理依赖模型中的对象,并且不应该在注入之后出现引用。谁会打电话给你的repository
  • 在什么阶段注入“IRepositories”。
  • 恐怕我不太明白你的问题。 repository 实现了一个接口。如果消费者对象 csn 不承载 that 接口,则它无法获得对它不支持的 repositiry 的引用。不是吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 2019-11-24
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多