007.ASP.NET MVC控制器依赖注入

时间:2023-01-08 14:35:44

原文链接:http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be

前言:在这篇文章中,我将通过一个demo,直截了当地说明依赖注入在MVC框架中的使用。

内容列表:

  1.介绍

  2.为什么使用控制器依赖注入

  3.控制器静态结构

  4.自定义控制器

  5.Framework中控制器的创建

  6.为什么使用控制器工厂模式

  7.控制器工厂模式

    7.1.目标1

    7.2.目标2

  8.使用MEF实现控制器工厂模式

  9.重点补充

一:介绍

  007.ASP.NET MVC控制器依赖注入

  首先简单地说明控制器在MVC框架中要做的几件事情

  1.接收HTTP请求

  2.处理HTTP请求

  3.操作客户端输入的数据

  4.发送回复给客户端

  5.作为Model和View的中转站

007.ASP.NET MVC控制器依赖注入

  MVC框架在运行时自己创建控制器对象,有一个先决条件,控制器类的构造函数是无参的。如果你想传递一个对象作为控制器的参数,这种情况我们又该如何处理?创建这种类型的控制器会失败,我们需要创建自己的控制器,将控制器参数注入到控制器。

  有多种方式可以将参数注入到控制器的构造方法中

  1.设置属性

  2.通过方法

  3.构造方法

  在这篇文章中,我将解释如何使用控制器注入到MVC中的构造函数中。如果不使用自定义控制器工厂模式,控制器注入是无法实现的。当然我也会解释如何创建简单的控制器工厂,然后注册到MVC框架。我也会展示一种方法注入控制器,使用MEF。

二.为什么使用控制器注入

  在现实的程序开发中,你会看到绝大多数的MVC程序需要注入它所依赖的组件。你可以直接创建组件在控制器中,而不需要注入它们。在这种情况下,组件和控制器紧密结合,如果一个组件的扩展发生了改变,或者一个新版本的组件要使用,你就需要改变控制器中的实现(PS:讲解为什么使用控制器注入)

  当你想使用单元测试的时候,另一种困难你可能会遇到。你不能测试这些控制器在一个独立的单元。你不能模仿一些新的特性,如果不能模仿,你将不能成功运行你的代码在一个独立的环境。

三.控制器静态结构

  MVC框架中的控制器结构是定义在一个叫Controller的抽象类中,如果你想创建一些控制器,首先你需要创建一个类,从抽象类Controller中继承,UML类图如下:

007.ASP.NET MVC控制器依赖注入

  所有的控制器都有一个根接口IController,抽象类ControllerBase从它去实现自己的方法。另一个抽象类从ControllerBase中继承,这个类就是Controller,所有的自定义的控制器类都要从Controller中继承,或者从它的子类中继承。

四.简单的自定义控制器

  如果你创建一个MVC工程,你将会得到两个控制器,AccountController和HomeController

007.ASP.NET MVC控制器依赖注入

007.ASP.NET MVC控制器依赖注入

  如果你去看HomeController中的代码实现,你会发现它没有自己的构造方法。

 public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
}

我们都知道这里没有一个构造方法,但在编译时会创建一个无参的构造方法。

 ublic class HomeController : Controller
{
public HomeController()
{
}
}

现在我将要创建一个ILogger接口及它的一个实现类DefaultLogger类,Home控制器会使用ILogger类型的对象作为参数,注入到它的控制器构造方法中。

 public interface ILogger
{
void Log(string logData);
}
public class DefaultLogger : ILogger
{
public void Log(string logData)
{
System.Diagnostics.Debug.WriteLine(logData, "default");
}
}

带参ILogger的Home控制器构造方法如下:

 public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILogger logger)
{
_logger = logger;
}
}

直到现在你也没找到我们在什么地方实例化了DefaultLogger对象,也不知道如何传递这个对象到控制器的构造方法中,在编写代码阶段程序不会报错,但是在运行代码会报错,如下:

007.ASP.NET MVC控制器依赖注入

看上面的线程记录,DefaultControllerActivator对象会抛出一个异常MissingMethonException。如果你到MSDN,找这个异常是如何引发的,你会发现找到不到适当的方法。看接下来的异常InvalidOperationException,它确实包含了MissingMethodException,将下来你会看到更加有用的信息,确保在控制器构造方法中有一个带参数的构造方法。如果想让代码工作正常,我必需要加带一个参数的构造方法,框架会创建控制器对象通过我们创建的那个构造方法。问题在于,我们如何传递一个一个DefaultLogger对象到这个控制器。请继续你好练习,我们接着往下看。

五.MVC框架是如何创建控制器对象

  在我们开始注入DefaultLogger对象到HomeController之前,我们要有一个概念,MVC框架是如何创建一个控制器对象的。IControllerFactory接口的主要责任就是创建控制器对象。DefaultControllerFactory是框架默认提供的可扩展的类。如果你添加一个无参的构造方法,然后设置一个断点,你将会发现程序在这一刻,将停留在这里。

007.ASP.NET MVC控制器依赖注入

看上面的图片,你可以看到IControllerFactory类型的一个DefaultControllerFactory对象,DefaultControllerFactory有一些方法,如:Create,GetControllerInstance,CreateController,这些方法将会创建一个HomeController对象,MVC框架是开源的,如果你想知道更多的方法,可以下载官方的资源,自己去阅读。你看调试的代码,你可以看到DefaultControllerFactory对象被CurrentControllerFactory

007.ASP.NET MVC控制器依赖注入

六.为什么要自定义控制器工厂

现在我们知道默认的控制器工厂使用一个无参的构造方法创建一个控制器对象。我们可以注入自己的带参的控制器构造方法。

 public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController():this(new DefaultLogger())
{
}
public HomeController(ILogger logger)
{
_logger = logger;
}
}

我发现许多的开发者都对上面依赖注入有所误解,它不是一个依赖注入的形式。这个确实违反了组件的原则。而这个原则的愿意是:上层的模块不能依赖于低层级的模块,双方都要依赖于抽象层,细节要在体现在抽象层。在上面的代码中,HomeController创建了自己的DefaultLogger对象。它直接依赖于ILogger接口的扩展(DefaultLogger),如果在将来一个新的扩展(扩展了ILogger接口),我们需要修改我们HomeController中的方法,所以我们需要使用适当的方法去注入我们的组件。我们要使用一个带参的构造方法去注入我们的ILogger 组件,但是默认的 DefaultControllerFactory不支持我们这么做,所以我们要创建自己的控制器工厂。

七.自定义控制器工厂

  我使用两种方法展示如何创建自己的控制器工厂。

  7.1途径1

  我们可以创建一个新的控制器工厂,扩展了IControllerFactory接口,假定我们自定义的控制器工厂的名称叫CustomControllerFactory,如下

 public class CustomControllerFactory : IControllerFactory
{
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
ILogger logger = new DefaultLogger();
var controller = new HomeController(logger);
return controller;
}
public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(
System.Web.Routing.RequestContext requestContext, string controllerName)
{
return SessionStateBehavior.Default;
}
public void ReleaseController(IController controller)
{
IDisposable disposable = controller as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}

现在第一步,我们需要将CustomControllerFactory注册到MVC框架,完成这件事要在Application_Start事件中书写代码。

 public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
RegisterCustomControllerFactory ();
}
}
private void RegisterCustomControllerFactory ()
{
IControllerFactory factory = new CustomControllerFactory();
ControllerBuilder.Current.SetControllerFactory(factory);
}

如果你运行你的程序,你会发现那个无参的构造方法没有被执行,那个带参的构造方法执行了。你的问题就这么简单的解决了。

007.ASP.NET MVC控制器依赖注入

你可以构建你的控制器工厂使用反射机制。

 public class CustomControllerFactory : IControllerFactory
{
private readonly string _controllerNamespace;
public CustomControllerFactory(string controllerNamespace)
{
_controllerNamespace = controllerNamespace;
}
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
ILogger logger = new DefaultLogger();
Type controllerType = Type.GetType(string.Concat(_controllerNamespace, ".", controllerName, "Controller"));
IController controller = Activator.CreateInstance(controllerType, new[] { logger }) as Controller;
return controller;
}
}

  7.2途径2

  这里方法不是去扩展IControllerFactory接口,而是去继承DefaultControllerFactory类,通过修改其中的方法。当然也要将控制器工厂注入到程序启动的事件中。代码如下:

 public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
ILogger logger = new DefaultLogger();
IController controller = Activator.CreateInstance(controllerType, new[] { logger }) as Controller;
return controller;
}
}

(去掉了MEF创建自定义控制器工厂的方法,因为自己也实在不能理解,但是要看啊)。

007.ASP.NET MVC控制器依赖注入的更多相关文章

  1. ASP.NET MVC IOC依赖注入之Autofac系列(二)- WebForm当中应用

    上一章主要介绍了Autofac在MVC当中的具体应用,本章将继续简单的介绍下Autofac在普通的WebForm当中的使用. PS:目前本人还不知道WebForm页面的构造函数要如何注入,以下在Web ...

  2. ASP.NET MVC IOC依赖注入之Autofac系列(一)- MVC当中应用

    话不多说,直入主题看我们的解决方案结构: 分别对上面的工程进行简单的说明: 1.TianYa.DotNetShare.Model:为demo的实体层 2.TianYa.DotNetShare.Repo ...

  3. ASP.NET MVC实现依赖注入

    在java的spring中有自动注入功能,使得代码变得更加简洁灵活,所以想把这个功能移植到c#中,接下来逐步分析实现过程 1.使用自动注入场景分析 在asp.net mvc中,无论是什么代码逻辑分层, ...

  4. ASP.NET MVC Autofac依赖注入的一点小心得(包含特性注入)

    前言 IOC的重要性 大家都清楚..便利也都知道..新的ASP.NET Core也大量使用了这种手法.. 一直憋着没写ASP.NET Core的文章..还是怕误导大家.. 今天这篇也不是讲Core的 ...

  5. ASP.NET MVC IOC依赖注入之Autofac系列开篇

    Autofac为IOC组件,实现控制反转,主要结合面向接口编程,完成较大程度的解耦工作. 使用IOC,必须面向接口编程,所谓的面向接口编程,即程序中依赖于抽象,而不依赖于具体实现. 需要所有的业务逻辑 ...

  6. ASP.NET MVC 控制器激活(一)

    ASP.NET MVC 控制器激活(一) 前言 在路由的篇章中讲解了路由的作用,讲着讲着就到了控制器部分了,从本篇开始来讲解MVC中的控制器,控制器是怎么来的?MVC框架对它做了什么?以及前面有的篇幅 ...

  7. ASP.NET MVC 控制器激活(二)

    ASP.NET MVC 控制器激活(二) 前言 在之前的篇幅中,用文字和图像来表示了控制器的激活过程,描述的角度都是从框架默认实现的角度去进行描述的,这样也使得大家都可以清楚的知道激活的过程以及其中涉 ...

  8. 详解ASP.NET MVC 控制器

    1   概述 在阅读本篇博文时,建议结合上篇博文:详解ASP.NET MVC 路由  一起阅读,效果可能会更好些. Controller(控制器)在ASP.NET MVC中负责控制所有客户端与服务端的 ...

  9. 【ASP.NET MVC系列】浅谈ASP.NET MVC 控制器

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

随机推荐

  1. [转]MVC3缓存之一:使用页面缓存

    本文转自:http://www.cnblogs.com/parry/archive/2011/03/19/OutputCache_In_MVC3.html 在以前的WebForm的开发中,在页面的头部 ...

  2. UBoot常用命令手册

    UBoot常用命令手册 U-Boot还提供了更加详细的命令帮助,可以通过”?”显示支持的命令列表,通过help [CommandName]命令还可以查看每个命令的参数说明. 1.bootm bootm ...

  3. 记一个问题的AC

    今天突然做一道LCT的染色问题的时候突然想到一个两个月前一道没有AC的题目. 链接 大意是,给一个长度为10^4的序列,最多有255个不同的数字,有最多10^5次方个询问,对于每个询问 l,r 输出[ ...

  4. POP3是收邮件的协议,SMTP是发邮件的协议,IMAP是一种邮箱通信协议。

    我也是第一次接触这种服务,是因为我自己在做一个小小的自动推送天气情况到自己邮箱.所以才碰到这个的/ 看一下标题,我们可以先这样理解. POP3(Post Office Protocol - Versi ...

  5. Vim自动补全神器YouCompleteMe的配置

    简介:YouCompleteMe号称Vim的自动补全神器,该项目在github的地址:YouCompleteMe:以下在10.0.1 build-1379776平台配置完成 插件安装操作: 1.确保V ...

  6. [Unity优化]UI优化(三):GraphicRebuild

    参考链接: https://blog.csdn.net/jingangxin666/article/details/80143176 调试过程: 1.修改Image的颜色 2.Graphic.SetV ...

  7. sqli-labs(二)

    第二关:sqli-labs的第二关是有报错信息的int类型的sql注入,输入id=1'后也会报错,如下图 可以看到报错信息种显示的是'' limit 0,1'  这处有错,其中前后两个单引符号是报错信 ...

  8. JPA和Hibernate到底是什么关系???

    转自:https://www.cnblogs.com/mosoner/p/9494250.html 在学习框架的过程中,发现学的东西很多,但是感觉他们之间的联系区别都不是很了解,知道JPA可以去实现持 ...

  9. Ceph 时钟偏移问题 clock skew detected 解决方案--- 部署内网NTP服务

    告警:HEALTH_WARN clock skew detected on mon.ip-10-25-195-6; 8 requests are blocked > 32 sec; Monito ...

  10. mysql索引之四:复合索引之最左前缀原理,索引选择性,索引优化策略之前缀索引

    高效使用索引的首要条件是知道什么样的查询会使用到索引,这个问题和B+Tree中的“最左前缀原理”有关,下面通过例子说明最左前缀原理. 一.最左前缀索引 这里先说一下联合索引的概念.MySQL中的索引可 ...