天天看点

在asp.net mvc4控制器中使用Autofac来解析依赖在asp.net mvc4控制器中使用Autofac来解析依赖

我们的代码中打破(抽离)依赖无非是为了增强可维护性、可测试性和灵活性。在前面的帖子我在MVC应用程序创建了一些严重的依赖性。HomeController实例化一个存储库。这个存储库调用外部系统(来获取)数据。其情形是位于Windows Azure的存储表。过于依赖于外部系统,单元测试将变得冗长繁琐(甚至不可靠)。Jeremy Miller 关于一个好的单元测试的质量写了一篇不错的博客中,他说:

但是在我们能做到这一点之前,我们首先需要重构出所有这些依赖项。为此,我们在这些依赖对象之间创建了一些小接口。然后我们配置一个IoC容器,负责注入适当的依赖关系以便于在需要的时候用到。在这个示例中,我们使用Autofac,但它也可以是任何其他的.NET的loc容器。

在这个例子中,我们有一个简单的MVC 4应用程序用来列举出奥运金牌的得主。这些都从一个SQL数据库用Entity Framework检索到的数据。数据检索过程封装在一个存储库中。但是在HomeController中通过新建一个GoldMedalWinnersRepository实例, 我们已经创建了一个永久的隐藏的依赖。

测试该控制器迫使我们使用/测试存储库逻辑。让我们先解决这个依赖。为了打破与外部类之间的依赖,可以让构造函数应该要求这些依赖项(作为参数传入)。所以我们可以从HomeController中移除存储库的实例化,而改用构造函数传入参数:

好的,现在构造函数明确阐述了它的所有依赖项。但是如果我们测试控制器我们仍然需要处理存储库调用数据库的(逻辑)。为了使控制器的测试独立于存储库(逻辑),我们需要传递一个虚拟存储库版本。这种方式我们完全控制对象的内部运作,而测试真正的控制器。要做到这一点,我们需要创建一个存储库的抽象;下面是接口:

稍后我们将看到,存储库的构造函数也有一个依赖项。它需要一个Entity Framework DbContext来正常运作。所以我们需要为此创建一个抽象(接口);IGoldMedalWinnersContext:

在让我们的存储库(类)的构造函数要求一个这个接口的实现(作为传入阐述),这样我们就成功的解耦了。

这时我们可以传入实现了接口的任何存储库类。在我们的单元测试中,很容易伪造,复制或模拟存储库和dbcontext(来做一个伪库以便于排除数据库的因素)。

这是很好的,但是我们在哪里实例化存储库?为此,我们可以使用一个IoC容器。这个神奇的东西可以通过配置,在必要时,可为控制器提供合适的存储库库时。在这个示例中,我们使用Autofac。我们可以很容易的从Nuget安装 Autofac ASP.NET MVC3 Integration package。它还适用于MVC4并负责安装所需的所有的我们的MVC应用程序需要的核心依赖。

一旦安装,我们可以根据需要配置Autofac来解析所有依赖项。为了演示,我们在MVC项目的App_start文件夹下创建一个配置类。它有一个静态的名为RegisterDependencies Autofac的方法,在这里我们可以启用Autofac。

我们新建一个Autofac ContainerBuilder,然后调用RegisterControllers来(注册整个) MVC程序集。这种方法用AutofacDependencyResolver注册所有在应用程序的控制器。每当MVC要求访问控制器时,这个解析器就返回适当的控制器。

然后我们调用RegisterType注册 GoldMedalWinnersRepository。在这里我们配置成:每当我们需要一个IGoldMedalWinnersRepository, Autofac必须返回一个GoldMedalWinnersRepository的实例。我们将生命周期设置为了InstancePerHttpRequest。我们同样的方式注册了GoldMedalWinnersContext。我们构建的容器,并为我们的容器的AutofacDependencyResolver设置了解析器MVC DependencyResolver 。

在MVC应用程序中的全局的.asax文件中,在所有其他MVC注册之前,我们调用了IoC配置类的RegisterDependencies方法,这样就可以了(我们准备好了)。

这就是全部(目前为止)。当我们启动应用程序,Autofac会做一个事情然后为控制器提供适当的实例化了带有适当的dbcontext的存储库。如果我们编写单元测试,然而,Autofac不会为我们的控制器提供存储库,因此我们可以注入一些假的,副本或仿制版本。这正是我们需要的。