如何为MVC4 / VS2012 / Web API注入控制器

时间:2013-02-12 21:21:16

标签: asp.net-web-api dependencies code-injection

我已阅读或试图阅读太多“如何”,并且已经无处可去。统一? System.Web.Http.Dependencies? Ninject? StructureMap?啊。我只想要一些简单有效的东西!我只是无法弄清楚目前的状态是什么。存在截然不同的方法,并且示例似乎是不完整的。哎呀最好的领导有一个样本项目...我无法加载到VS2010或2012. ARG!我觉得应该最多半小时,然后继续前进,我每天都会花费3/4的时间!这只是管道!

我有一个基于泛型的存储库来处理所有支持相同操作的数据集。

IRepository

我想控制每个数据集绑定到哪个存储库。这将允许我将所有内容绑定到测试XML存储库,随着项目的进展将它们转换到SQL存储库。

我肯定会感谢一些帮助实现这一目标!谢谢!

1 个答案:

答案 0 :(得分:3)

听起来像你在几年前的状态。

注意,如果您需要任何进一步的帮助,我会向您发送一些代码。将所有代码放在这里很难。

我试着解释我正在进行的项目中的当前架构。这篇文章有点长篇大论,但我想让大家了解一下如何使用IOC在很多方面帮助你。

所以我使用Ninject。在尝试使用Castle Windsor一段时间之后,我发现Ninject很容易起床和跑步。 Ninject有一个很酷的网站,可以帮助你入门。

首先,我的项目结构如下:(自上而下及其MVC)

查看 - 剃刀 ViewModel - 我为每个视图使用1个视图模型

ViewModelBuilder - 为我的视图构建我的视图模型(用于从我的控制器中抽象代码,使我的控制器保持整洁)

AutoMapper - 将域实体映射到我的视图模型

控制器 - 调用我的服务层以获取域实体

域名实体 - 我域名的表示

ServiceLayer(业务层) - 调用我的存储库层以获取域实体或这些的集合

再次

AutoMapper - 将我的第三方供应商的自定义类型映射到我的域实体

RepositoryLayer - 对我的数据存储进行CRUD操作

这是一个层次结构,但域实体类似于旁边,并在几个不同的层中使用。

注意:本文中提到的一些额外工具是:

AutoMapper - 将实体映射到其他实体 - 无需编写大量映射代码

Moq - 允许您模拟单元测试的内容。这将在后面提到。

现在,关于Ninject。

每个图层都标有界面。必须这样做才能让Ninject对自己说出来。

  

当我发现IVehicleRepository用真实的VehicleRepository注入它时,如果我需要假的话,甚至用FakeVehicleRepository注入它。

(这与您的评论有关 - "这将允许我将所有内容绑定到测试XML存储库")

现在每个图层都有一个contstructor,以便Ninject(或任何其他IOC容器)可以注入它所需的内容:

public VehicleManager(IVehicleRepository vehicleRepository)
{
    this._vehicleRepository = vehicleRepository;
}

VehicleManager在我的serviceLayer中(不要与任何与Web服务有关的东西混淆)。服务层实际上就是我们所说的业务层。似乎很多人都在使用服务这个词。 (尽管我觉得它很烦人,因为它让我想到了Web服务或WCF,而不仅仅是一个业务层......无论如何......)

现在没有深入了解Ninject设置的细节,我的NinjectWebCommon.cs中的以下代码行告诉ninject要做什么:

kernel.Bind<IVehicleRepository>().To<VehicleRepository>().InRequestScope();

这说:

  

Hey Ninject,当我要求IVehicleRepository时,我给出了VehicleRepository的具体实现。

如前所述,我可以用FakeVehicleRepository替换VehicleRepository,这样我就不必从真正的数据库中读取。

因此,正如您现在可以想象的那样,每一层都只依赖于接口。

我不知道你做了多少单元测试,但是你也可以想象如果你想对你的服务层进行单元测试并且它具有对你的存储库层的具体引用那么你将无法进行单元测试。实际上访问您的存储库,从而从真实的数据库中读取。

请记住,单元测试称为单元测试,因为它只测试一件事。因此,单词UNIT。因为一切只知道接口,这意味着您可以在服务层上测试方法并模拟存储库。

因此,如果您的服务层有这样的方法:

public bool ThisIsACar(int id)
{
   bool isCar = false;
   var vehicle = vehicleRepository.GetVehicleById(id);

   if(vehicle.Type == VehicleType.Car)
   {
       isCar = true;
   }
   else
   {
       isCar = false;
   }
}

您不希望调用vehicleRepository,因此您可以使用Moq为VehicleRepository提供的内容。如果它实现了接口,你几乎只能模拟东西。

So your unit test would look like this (some pseudo code here):
        [TestMethod]
        public void ServiceMethodThisIsACar_Returns_True_When_VehicleIsACar()
        {
            // Arrange
            _mockRepository.Setup(x => x.ThisIsACar(It.IsAny<int>)).returns(new Car with a type of VehicleType.Car)

            // Act
            var vehicleManager = new VehicleManager(_mockVehicleRepository.Object);
            var vehicle = vehicleManager.ThisIsACar(3);

            // Assert
            Assert.IsTrue(vehicle.VehicleType == VehicleType.Car)
        }

正如您所看到的,此时非常简化,您只想测试服务层中的IF语句,以确保结果正确。

您将在自己的单元测试中测试您的存储库,如果您正在使用它,可能会模拟实体框架工作。

所以,总的来说,我会说,使用IOC容器让你起得最快,跑得最快,痛苦最少。

我也会说,尽量尝试单元测试。出于几个不同的原因,这很好。显然它会测试你编写的代码,但它也会立即显示你是否做了一些愚蠢的事情,比如新建一个具体的存储库。您很快就会发现在单元测试中没有模拟界面,这将导致您返回并重构代码。

我发现,与国际奥委会一起,需要一段时间才能得到它。它混淆了你的垃圾,直到有一天它只是点击。在那之后,你很想知道没有它你是如何生活的。

以下列出了我无法生活的事情 Automapper 起订量 流畅的验证 Resharper - 有些人讨厌它,我喜欢它,主要是因为它的单元测试用户界面。

无论如何,这太长了。让我知道你的想法。

感谢 RuSs