之前的文章介绍了MVC如何通过ControllerFactory及ControllerActivator创建Controller,而Controller又是如何通过ControllerBase这个模板完成了功能的拓展及业务的执行。这一系列MVC类型的设计处处都体现了IoC的设计原则,所以本章将从以下几点对ASP.NET MVC中的IoC进行介绍:
  ● 什么是IoC
  ● ASP.NET MVC中的IoC
  ● 什么是DI
  ● IoC容器与依赖解析器(Dependency Resolver)
  ● ASP.NET MVC中使用DI

什么是IoC

  IoC(控制反转,Inversion of Control)它是软件开发中的一种设计原则,意思就是把控制权从自身(这里的自身大部分指代的是业务代码)转给其它对象来控制。IoC的意图是将任务的执行从实现中解耦,可以专注于模块任务的设计(如:操作数据库的组件,可以有操作SQL Server和My SQL的),系统本身不会关注这个模块做了什么,同时当系统替换了这个模块后不会对系统造成影响。在软件开发中有几种常见的基于IoC思想的实现:
  ● 工厂模式
  ● 模板模式
  ● 策略模式
  ● 依赖注入

  以上模式都是将实现解耦,便于拓展。特别是依赖注入(DI,Dependency Injection),看到IoC更多想到的就依赖注入。
  依赖倒置原则(DIP):上面说了那么多的实现,但有一个根本的原则就是依赖倒置原则“高层模块不依赖于低层模块,它们都应该依赖于抽象,抽象不应该依赖于实现,实现应该依赖于抽象”。在.Net中就是使用接口和抽象类对业务和对象进行抽象,抽象与实现分开,如果放弃了这一原则实现依赖于实现,那么就反转不了了(lll¬ω¬)。

ASP.NET MVC中的IoC

  之前的文章中分析了ASP.NET MVC中Controller的创建过程和执行中主要的参与对象分别有:
  ● DefaultControllerFactory:工厂模式。
  ● DefaultControllerActivator:依赖注入(注:创建Controller时首先从依赖解析器中获取Controller实例,无法获取才自己创建)。
  ● ControllerBase:模板模式(注:ControllerBase定义了Execute模板方法调用抽象方法ExecuteCore,ExecuteCore的实现在子类中)。

  这些对象的设计思想就是IoC。

什么是DI

  DI(Dependency Injection,依赖注入),它其实是两个部分,第一个是“依赖”,然后才是“注入”。
  1. 依赖:简单来说就是需要,在面向对象的一个类里面它“需要”其它类型来完成工作。如在MyBlog中的逻辑类需要仓储类来操作数据库,这种情况下就是逻辑类依赖仓储类:

  

  2. 注入:其实就是对类的依赖赋值,常用的注入的方式是:构造注入、属性注入、方法注入,说白了就是通过构造方法、属性(Setter方法)以及方法将依赖的对象传入类的实例中并赋值。但要注意的是这个“注”字,为什么不直接用赋值?
  举个栗子:制作一个水球,要么留一个注水口,要么在制作的时候把水灌入然后封死。
  对于有注水口的水球,在使用时如果注入红色的水,就变成了红色的水球,注入黄色的就是黄色的,而被封死的水球在制作时灌了什么颜色的水就是什么颜色的。
  而在程序开发中更是如此,以MyBlog为例,业务逻辑类通过仓储类来获取数据,业务类可以“封死”只用SQL Server的操作类,也可以开放,在运行时将数据操作这个实例“注入”,那么注入SQL Server操作类就使用SQL Server,注入MySQL的就使用My SQL。
  对水球注水首先要有水,其次是水球要有注水口,那么在程序里的“水”和“注水口”是什么?

IoC容器与依赖解析器(DependencyResolver)

  在程序中所谓的“水”应该是那些抽象的实现,或者说实现了抽象的类型。比如操作SQL Server的仓储类和操作MySQL的仓储操作类。那么这些“水”要放在哪里?“水”当然要放在容器里,所以就有了IoC容器。
  那IoC容器是什么?它可以简单到只是一个实例的数组或字典,通过实例的类型(或实现的父类型、接口等)从这个字典或数组中获取对应的实例,也可以是像Autofac、Ninject这些复杂成熟的IoC容器组件。
  以下代码分别是AutoFac和NinJect官方文档中为容器注“水”的过程:
  Ninject:https://github.com/ninject/ninject

  

  AutoFac:https://autofac.org/

  

  有了装满“水”的容器,想要把“水”注入到程序中,那就需要“注水口”依赖解析器(Denpendency Resolver)的支持。
  以下代码就是DefaultControllerActivator创建Controller的代码:

  

  想象一下,把上面的“注水口”连接到装满“水”的容器中,不是就能够把需要的东西注入到需要的位置吗?

ASP.NET MVC中使用DI

  DI的使用有两个必要条件就依赖容器和依赖解析器,ASP.NET中建议使用成熟的依赖容器,如Autofac等,它们提供了强大的功能并支持多种组件注册到容器以及注入方式。而关于依赖解析器在ASP.NET MVC中是有默认解析器的,以下是ASP.NET MVC的解析器定义:

  

  它实际的作用是通过Current属性获取一个IDependencyResolver的对象。
  DependencyResolver中内置了一些实现该接口的对象,但是几乎是无用的如下图:

  

  所以一般情况下如果在ASP.NET中都是实现IDependencyResolver接口然后通过DependencyResolver.SetResolver方法修改默认的依赖解析器。

  在ASP.NET MVC中,使用依赖注入最频繁的就是Controller,Controller作为业务逻辑执行的入口,它依赖业务逻辑的组件,而业务逻辑组件又依赖数据操作组件等等。所以在ASP.NET MVC中使用依赖注入实际上就是把Controller及其依赖都放入容器里,然后创建Controller时从容器中获取即可。根据Controller的创建流程将使用方法分为以下几种:
  1. 实现IDependencyResolver接口然后通过DependencyResolver.SetResolver方法修改默认的依赖解析器(替换默认的“注水口”)。
  2. 实现IControllerActivator接口,然后在创建DefaultControllerFactory时将其以参数的形式传入到DefaultControllerFactory中(在ControllerActivator中添加自己的“注水口”,并替换掉原有的ControllerActivator)。
  3. 继承DefaultControllerFactory使用从容器中获取Controller的方法将原有的GetControllerInstance方法替换掉(添加“注水口”放置在ControllerFactory中,放弃ControllerActivator的使用)。

  注:由于在Controller类型中包含一个IDependencyResolver属性,所以方法2和方法3没有替换默认依赖解析器会导致Controller中使用该属性无法访问到真实的容器,如果需要在其基础上使用方法1将默认的依赖解析器替换掉。

小结

  IoC容器和依赖注入在软件开发中是一个非常中要的概念,现在主流的一些开发框架的核心都是基于依赖注入的,即框架中的所有组件如日志、缓存、队列等都会通过容器将其注入到使用的地方。本章主要以文字的形式介绍了IoC、DI的概念及其在ASP.NET MVC中的使用的三种方法,在下一篇文章中将会用代码的形式介绍如何使用这三种方法在ASP.NET MVC中实现依赖注入。

参考:

  https://en.wikipedia.org/wiki/Inversion_of_control

本文连接:http://www.cnblogs.com/selimsong/p/7682808.html

ASP.NET没有魔法——目录

ASP.NET没有魔法——ASP.NET MVC IoC代码篇

ASP.NET没有魔法——ASP.NET MVC IoC的更多相关文章

  1. ASP.NET没有魔法——ASP.NET MVC 与数据库大集合

    ASP.NET没有魔法——ASP.NET与数据库 ASP.NET没有魔法——ASP.NET MVC 与数据库之MySQL ASP.NET没有魔法——ASP.NET MVC 与数据库之ORM ASP.N ...

  2. ASP.NET没有魔法——ASP.NET MVC 路由的匹配与处理

    ASP.NET MVC的路由是MVC应用的一个核心也是MVC应用处理的入口,作为一个开发者,在正常情况下仅仅需要做的就是根据需求去定义实体.业务逻辑,然后在MVC的Controller中去调用.Vie ...

  3. ASP.NET没有魔法——ASP.NET MVC 过滤器(Filter)

    上一篇文章介绍了使用Authorize特性实现了ASP.NET MVC中针对Controller或者Action的授权功能,实际上这个特性是MVC功能的一部分,被称为过滤器(Filter),它是一种面 ...

  4. ASP.NET没有魔法——ASP.NET MVC使用Oauth2.0实现身份验证

    随着软件的不断发展,出现了更多的身份验证使用场景,除了典型的服务器与客户端之间的身份验证外还有,如服务与服务之间的(如微服务架构).服务器与多种客户端的(如PC.移动.Web等),甚至还有需要以服务的 ...

  5. ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(下篇)

    上一篇<ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)>文章介绍了ASP.NET MVC模型绑定的相关组件和概念,本章将介绍Controller在执行时是如何通过这 ...

  6. ASP.NET没有魔法——ASP.NET MVC Razor与View渲染

    对于Web应用来说,它的界面是由浏览器根据HTML代码及其引用的相关资源进行渲染后展示给用户的结果,换句话说Web应用的界面呈现工作是由浏览器完成的,Web应用的原理是通过Http协议从服务器上获取到 ...

  7. ASP.NET没有魔法——ASP.NET MVC Razor与View渲染 ASP.NET没有魔法——ASP.NET MVC界面美化及使用Bundle完成静态资源管理

    ASP.NET没有魔法——ASP.NET MVC Razor与View渲染   对于Web应用来说,它的界面是由浏览器根据HTML代码及其引用的相关资源进行渲染后展示给用户的结果,换句话说Web应用的 ...

  8. ASP.NET没有魔法——ASP.NET 身份验证与Identity

    前面的文章中为My Blog加入了文章的管理功能(ASP.NET没有魔法——ASP.NET MVC使用Area开发一个管理模块),但是管理功能应该只能由“作者”来访问,那么要如何控制用户的访问权限?也 ...

  9. ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证

    ASP.NET Identity除了提供基于Cookie的身份验证外,还提供了一些高级功能,如多次输入错误账户信息后会锁定用户禁止登录.集成第三方验证.账户的二次验证等,并且ASP.NET MVC的默 ...

随机推荐

  1. 201521123107 《Java程序设计》第10周学习总结

    第10周作业-异常与多线程 1.本周学习总结 2.书面作业 1.finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中finally中捕获异常需要注意什么? 只有try块中 ...

  2. 201521123103 《Java程序设计》第三周学习总结

    一.本周学习总结 二.书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; pub ...

  3. 201521123032 《Java程序设计》第11周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) ...

  4. 201521123016《Java程序设计》第14周学习总结

    1. 本周学习总结 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己的学号.姓名) 在自己建立的数据库上执行常见SQL语句(截图) - ...

  5. csv文件读取

    from urllib.request import urlopen from io import StringIO import csv data = urlopen("http://py ...

  6. 二分求最长上升子序列 二分LIS

    #include <iostream> #include <cstring> #define N 50010 using namespace std; int n; int n ...

  7. Java实现3DES加密--及ANSI X9.8 Format标准 PIN PAN获取PIN BlOCK

    1, 采用银联ANSI X9.8标准 PIN xor PAN获取PIN BlOCK 2, 采用3Des进行加密 参考: des和3Des加密算法实现 要点:因为3DES是对称加密算法,key是24位, ...

  8. C#中的两把双刃剑:抽象类和接口

    问题出现: 这也是我在学习抽象类和接口的时候遇到的问题,从我归纳的这三个问题,不难看出这也许是我们大多数程序员遇到问题的三个阶段, 第一阶段(基础概念):就象问题1一样,这部分人首先需要扫清基础概念的 ...

  9. 翻译连载 | 第 9 章:递归(下)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...

  10. 如何实现跨 Docker 主机存储?- 每天5分钟玩转 Docker 容器技术(73)

    从业务数据的角度看,容器可以分为两类:无状态(stateless)容器和有状态(stateful)容器. 无状态是指容器在运行过程中不需要保存数据,每次访问的结果不依赖上一次访问,比如提供静态页面的 ...