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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介:

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

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

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

在构造函数中明确声明依赖

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

using System.Web.Mvc;
using TestableMvcApp.DataContext;
using TestableMvcApp.Models;
using TestableMvcApp.Repositories;
 
namespace TestableMvcApp.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index(GoldMedalWinnersModel model)
        {
            ViewBag.Message = "Gold Medal Winners";
 
            var repository = new GoldMedalWinnersRepository(
                new GoldMedalWinnersContext());
 
            model.Winners = repository.GetAll();
 
            return View(model);
        }
    }
}

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

using System.Web.Mvc;
using TestableMvcApp.Models;
using TestableMvcApp.Repositories;
 
namespace TestableMvcApp.Controllers
{
    public class HomeController : Controller
    {
        private readonly GoldMedalWinnersRepository _repository;
 
        public HomeController(GoldMedalWinnersRepository repository)
        {
            _repository = repository;
        }
 
        public ActionResult Index(GoldMedalWinnersModel model)
        {
            ViewBag.Message = "Gold Medal Winners";
 
            model.Winners = _repository.GetAll();
 
            return View(model);
        }
    }
}
这是往正确方向的一小步。

调用抽象(接口/抽象类)

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

using System.Collections.Generic;
using TestableMvcApp.Pocos;
 
namespace TestableMvcApp.Repositories
{
    public interface IGoldMedalWinnersRepository
    {
        GoldMedalWinner GetById(int id);
        IEnumerable<GoldMedalWinner> GetAll();
        void Add(GoldMedalWinner goldMedalWinner);
    }
}
让我们改变控制器的构造函数要求传入一个抽象IGoldMedalWinnersRepository接口而不是实际GoldMedalWinnersRepository对象。
 
using System.Web.Mvc;
using TestableMvcApp.Models;
using TestableMvcApp.Repositories;
 
namespace TestableMvcApp.Controllers
{
    public class HomeController : Controller
    {
        private readonly IGoldMedalWinnersRepository _repository;
 
        public HomeController(IGoldMedalWinnersRepository repository)
        {
            _repository = repository;
        }
 
        public ActionResult Index(GoldMedalWinnersModel model)
        {
            ViewBag.Message = "Gold Medal Winners";
 
            model.Winners = _repository.GetAll();
 
            return View(model);
        }
    }
}
 
稍后我们将看到,存储库的构造函数也有一个依赖项。它需要一个Entity Framework DbContext来正常运作。所以我们需要为此创建一个抽象(接口);IGoldMedalWinnersContext:
using System.Data.Entity;
using TestableMvcApp.Pocos;
 
namespace TestableMvcApp.DataContext
{
    public interface IGoldMedalWinnersContext
    {
        DbSet<GoldMedalWinner> GoldMedalWinners { get; set; }
        DbSet<Country> Countries { get; set; }
        int SaveChanges();
    }
}
在让我们的存储库(类)的构造函数要求一个这个接口的实现(作为传入阐述),这样我们就成功的解耦了。
using System.Collections.Generic;
using System.Linq;
using TestableMvcApp.DataContext;
using TestableMvcApp.Pocos;
 
namespace TestableMvcApp.Repositories
{
    public class GoldMedalWinnersRepository : IGoldMedalWinnersRepository
    {
        private readonly IGoldMedalWinnersContext _goldContext;
 
        public GoldMedalWinnersRepository(IGoldMedalWinnersContext goldContext)
        {
            _goldContext = goldContext;
        }
 
        #region IGoldMedalWinnersRepository Members
 
        public GoldMedalWinner GetById(int id)
        {
            return _goldContext.GoldMedalWinners.Find(id);
        }
 
        public IEnumerable<GoldMedalWinner> GetAll()
        {
            return _goldContext.GoldMedalWinners.ToList();
        }
 
        public void Add(GoldMedalWinner goldMedalWinner)
        {
            _goldContext.GoldMedalWinners.Add(goldMedalWinner);
            _goldContext.SaveChanges();
        }
 
        #endregion
    }
这时我们可以传入实现了接口的任何存储库类。在我们的单元测试中,很容易伪造,复制或模拟存储库和dbcontext(来做一个伪库以便于排除数据库的因素)。

使用IoC容易来解析依赖

这是很好的,但是我们在哪里实例化存储库?为此,我们可以使用一个IoC容器。这个神奇的东西可以通过配置,在必要时,可为控制器提供合适的存储库库时。在这个示例中,我们使用Autofac。我们可以很容易的从Nuget安装 Autofac ASP.NET MVC3 Integration package。它还适用于MVC4并负责安装所需的所有的我们的MVC应用程序需要的核心依赖。
 
一旦安装,我们可以根据需要配置Autofac来解析所有依赖项。为了演示,我们在MVC项目的App_start文件夹下创建一个配置类。它有一个静态的名为RegisterDependencies Autofac的方法,在这里我们可以启用Autofac。
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using TestableMvcApp.DataContext;
using TestableMvcApp.Repositories;
 
namespace TestableMvcApp.App_Start
{
    public class IocConfig
    {
        public static void RegisterDependencies()
        {
            var builder = new ContainerBuilder();
            builder.RegisterControllers(typeof (MvcApplication).Assembly);
 
            builder.RegisterType<GoldMedalWinnersRepository>()
                .As<IGoldMedalWinnersRepository>()
                .InstancePerHttpRequest();
 
            builder.RegisterType<GoldMedalWinnersContext>()
                .As<IGoldMedalWinnersContext>()
                .InstancePerHttpRequest();
 
            IContainer container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
    }
}
我们新建一个Autofac ContainerBuilder,然后调用RegisterControllers来(注册整个) MVC程序集。这种方法用AutofacDependencyResolver注册所有在应用程序的控制器。每当MVC要求访问控制器时,这个解析器就返回适当的控制器。
 
然后我们调用RegisterType注册 GoldMedalWinnersRepository。在这里我们配置成:每当我们需要一个IGoldMedalWinnersRepository, Autofac必须返回一个GoldMedalWinnersRepository的实例。我们将生命周期设置为了InstancePerHttpRequest。我们同样的方式注册了GoldMedalWinnersContext。我们构建的容器,并为我们的容器的AutofacDependencyResolver设置了解析器MVC DependencyResolver 。
 
在MVC应用程序中的全局的.asax文件中,在所有其他MVC注册之前,我们调用了IoC配置类的RegisterDependencies方法,这样就可以了(我们准备好了)。
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using TestableMvcApp.App_Start;
 
namespace TestableMvcApp
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            IocConfig.RegisterDependencies();
 
            AreaRegistration.RegisterAllAreas();
 
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}
这就是全部(目前为止)。当我们启动应用程序,Autofac会做一个事情然后为控制器提供适当的实例化了带有适当的dbcontext的存储库。如果我们编写单元测试,然而,Autofac不会为我们的控制器提供存储库,因此我们可以注入一些假的,副本或仿制版本。这正是我们需要的。
目录
打赏
0
0
0
0
94
分享
相关文章
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
326 2
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
106 2
Spring MVC中的控制器:@Controller注解全解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序控制层的核心。它不仅简化了控制器的定义,还提供了灵活的请求映射和处理机制。本文将深入探讨`@Controller`注解的用法、特点以及在实际开发中的应用。
231 0
ASP.NET连接SQL数据库:实现过程与关键细节解析an3.021-6232.com
随着互联网技术的快速发展,ASP.NET作为一种广泛使用的服务器端开发技术,其与数据库的交互操作成为了应用开发中的重要环节。本文将详细介绍在ASP.NET中如何连接SQL数据库,包括连接的基本概念、实现步骤、关键代码示例以及常见问题的解决方案。由于篇幅限制,本文不能保证达到完整的2000字,但会确保
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
267 0
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
93 0
单元测试问题之在Spring MVC项目中添加JUnit的Maven依赖,如何操作
单元测试问题之在Spring MVC项目中添加JUnit的Maven依赖,如何操作
饼干探秘:深入Spring MVC中获取Cookie数据的技术解析
饼干探秘:深入Spring MVC中获取Cookie数据的技术解析
112 3
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
103 0

热门文章

最新文章

推荐镜像

更多