【问题标题】:Using Ninject in a SOLID application architecture在 SOLID 应用程序架构中使用 Ninject
【发布时间】:2011-08-03 00:29:29
【问题描述】:

我从 MVC3 开始,想使用一些灵活的架构,所以我读了几十篇博客,一本书(Pro ASP.NET MVC 3),阅读了关于 SOLID 原理的内容,最后得到了我喜欢的应用程序结构(或者至少到目前为止我是这么认为的,因为我还没有在它上面构建任何东西):

在这个结构中:

  • 域包含 POCO 类并定义服务接口
  • Services 实现服务接口并定义存储库接口
  • 数据实现存储库接口
  • WebUI 和域使用服务
  • 服务使用存储库
  • WebUI、服务和数据依赖于 POCO 类的域

Domain 使用 Services 的主要原因是在 POCO (IValidatable) 类的 Validate 方法上验证唯一键。

我开始使用这种结构构建一个参考应用程序,但到目前为止,我遇到了两个问题:

  1. 我正在使用 Data.Tests 项目和存储库的单元测试,但还没有找到一种方法来在模型上注入(使用 Ninject)服务的实现(在构造函数中或其他方式中) ,因此 Validate 方法可以调用服务上的 CheckUniqueKey。

  2. 我没有找到任何关于将 Ninject 连接到 TEST 项目的参考资料(很多用于 WebUI 项目)。

我在这里想要实现的是能够从 EF 切换到 DAPPER 之类的其他东西,只需更改 DATA 程序集。

更新

现在(截至 2011 年 8 月 9 日)Ninject 正在工作,但我认为我遗漏了一些东西。

我有一个带有两个构造函数的 CustomerRepository:

public class CustomerRepository : BaseRepository<Customer>, ICustomerRepository
{
    // The repository usually receives a DbContext
    public CustomerRepository(RefAppContext context)
        : base(context)
    {
    }

    // If we don't receive a DbContext then we create the repository with a defaulte one
    public CustomerRepository()
        : base(RefApp.DbContext())
    {
    }

    ...
}

关于TestInitialize:

// These are for testing the Repository against a test database

[TestInitialize()]
public void TestInitialize()
{
    // Context used for tests
    this.context = new RefAppContext();

    // This is just to make sure Ninject is working, 
    // would have used: repository = new CustomerRepository(context);

    this.kernel = NinjectMVC3.CreateKernel();

    this.kernel.Rebind<ICustomerRepository>().To<CustomerRepository>().WithConstructorArgument("context", context);

    this.repository = kernel.Get<ICustomerRepository>();

}

关于客户类:

public class Customer : IValidatableObject 
{
    ...

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        // I want to replace this with a "magic" call to ninject
        CustomerRepository rep = new CustomerRepository();

        Customer customer = rep.GetDupReferenceCustomer(this);

        if (customer != null)
            yield return new ValidationResult("Customer \"" + customer.Name + "\" has the same reference, can't duplicate", new [] { "Reference" });
    }

    ...
}

在这种情况下使用 Ninject 的最佳方式是什么?

我们将不胜感激。

回答,有点

到目前为止,我会考虑这个问题。我可以让 Ninject 工作,但看起来要实现 SOLID 的依赖倒置原则 (DIP) 需要更多时间。

在这方面,我不得不将域、服务和数据混为一谈,我将在其他时间提出另一个问题,并让项目暂时按常规方式进行。

谢谢大家。

【问题讨论】:

  • 建议取出 Ninject 参考并将其更改为 DI,因为答案不会(并且不应根据您的特定容器进行更改)。我还会添加架构或找到更多标签。
  • @Ruben 你是对的,在同一个句子中使用“Ninject”和“应用程序架构”听起来不太正确,只是在这种情况下我正在尝试非常解决一个问题特定于 Ninject。
  • 我会将更新放到一个新问题中,因为它完全是另一个主题,与第一个主题没有太多共同之处。否则不会有很多人会阅读您的新问题。
  • @Remo,你说得对,除此之外,我意识到我正在尝试同时(对我而言)做两件复杂的事情,儿子,我将首先尝试让 Ninject 在单个程序集中工作,然后我会尝试将其拆分出来。

标签: asp.net-mvc-3 architecture ninject solid-principles


【解决方案1】:

单元测试应该在没有 Ninject 的情况下进行。只需创建一个被测对象的实例并手动为每个依赖项注入一个模拟。

对于集成测试,您可以使用内核,包括来自应用程序引导程序的所有绑定,并重新绑定您想用 Mock 替换的所有内容。例如将 Session 绑定替换为使用内存数据存储而不是真实数据库的绑定。

【讨论】:

  • 现在我正在做集成测试,因为我正在测试访问实际数据库的存储库。 Ninject 的使用是为了能够最终用其他东西替换服务层。在这种情况下, POCO.Validate 方法使用接口中定义的 Service 方法。重点是,例如如何解析 Customer.Validate 方法中的服务接口,以便我可以使用 CustomerServices.FindCustomerByEmail(Email) 方法检查是否有其他客户使用相同的电子邮件。
  • @Miguel Veloso:更新集成测试
  • 我应该在哪里放置应用程序引导程序?测试项目中没有 Global.asax!
  • 进入测试设置。致电this.kernel = MyProject.App_Start.NinjectMVC3.CreateKernel(); this.kernel.Rebind&lt;ISomething&gt;.ToConstant(new Mock&lt;ISomething&gt;());
  • 我在 [ClassInitialize()] 上试过这个,但 VS 说我不能在静态方法中使用“this”,在 [TestInitialize()] 上,问题出在内核成员上。此外,我发现了几个障碍,我更新了原来的问题。
猜你喜欢
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多