Asp.net MVC企业级开发(01)---Autofac
1.1 控制反转
在面向对象设计的软件系统中,它的底层都是由N个对象构成的,各个对象之间通过相互合作,最终实现系统的业务逻辑。同时,对象之间的耦合关系是无法避免的,也是必要的,这是协同工作的基础。但是,伴随着工业级应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,架构师和设计师对于系统的分析和设计,将面临更大的挑战。对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。
耦合关系不仅会出现在对象与对象之间,也会出现在软件系统的各模块之间,以及软件系统和硬件系统之间。如何降低系统之间、模块之间和对象之间的耦合度,是软件工程永远追求的目标之一。为了解决对象之间的耦合度过高的问题,软件专家Michael Mattson 1996年提出了IOC理论,用来实现对象之间的“解耦”.
我们来看下面的示例。
示例1
|
public class EmailService { public void SendMessage() { Console.WriteLine("通过电子邮件发送消息"); } } public class MessageManager { private EmailService msgService; public MessageManager() { msgService=new EmailService(); } public void SendMsg() { msgService.SendMessage(); } } |
在示例1中,MessageManager 类依赖于EmailService类,两者之间存在耦合。 MessageManager类在构造函数内直接创建EmailService类的一个实例,换言之,MessageManager类精确的知道创建和使用了哪种类型的服务。这种耦合表示了代码的内部链接性。一个类知道与其交互的类的大量信息,我们称为高耦合。这就会增加软件修改的负担,因为修改一个类很可能破坏依赖于它的另一个类。
上面的代码设计还有一个问题:当MessageManager不想采用Email方式发送消息,而是采用其它方式,如微信,那么必须重新实现MessageManager类。
为了降低组件之间的耦合程度,一般采取两个独立但相关的步骤:
(1)在两块代码之间引入抽象层。
通常使用接口来代表两个类之间的抽象层。如实例2所示。
|
public interface IMessageService { void SendMessage(); } public class EmailService : IMessageService { public void SendMessage() { Console.WriteLine("通过电子邮件发送消息"); } } public class MessageManager { private IMessageService msgService; public MessageManager() { msgService=new EmailService(); } public void SendMsg() { msgService.SendMessage(); } } |
(2)把选择抽象实现的责任移到消费者的外部。
需要把EmailService类的创建移到MessageManager类的外面。
把依赖的创建移到使用这些依赖类的外部,这称为控制反转模式,之所以这样命名,是因为反转的是依赖的创建,正因为如此,才消除了消费者类对依赖创建的控制。
控制反转(Inversion of Control,即IOC)模式是抽象的:它只是表述应该从消费者类中移除依赖创建,而没有表述如何实现。
1.2 依赖注入
依赖注入(Dependence Injection,即DI)是一种控制反转的形式。其意思是自身对象中的内置对象是通过注入的方式进行创建。注入方式通常采用构造函数注入或属性注入。
1.2.1 构造函数注入
示例3
|
public class MessageManager { private IMessageService msgService; public MessageManager(IMessaageService service) { msgService=service; } public void SendMsg() { msgService.SendMessage(); } } |
示例3有一个显著的优点,它极大地简化了构造函数的实现。组件总是期望创建它的类能够传递需要的依赖。而它只需要存储IMessaageService接口的实例以便之后使用,不需要知道它自己的依赖项。另一个有点就是需求的透明性。任何要创建MessageManager类实例的代码都能查看构造函数,并精确的知道那些内容是使用该类必须的。
1.2.2 属性注入
顾名思义,该方式是通过设置对象上的公共属性而不是通过使用构造函数参数来注入依赖的。如示例4所示。
示例4
|
public class MessageManager { public IMessageService msgService {get; set;} public void SendMsg() { if (msgService ==null) { Throw new InvalidOperationException(); } msgService.SendMessage(); } } |
上面的两种注入方式,都需要手动提供所需的依赖项,也就意味着都需要我们知道如何来满足每一部分的需要。
依赖注入容器是一个使依赖解析变得简单的一种方式。
1.3 依赖注入框架---Autofac
Autofac是一款IOC容器框架,比较于其他的IOC框架,如Spring.NET,Unity,Castle等等框架,它很轻量级,性能上也很高。
1.3.1 Autofac 的使用
- 获取Autofac
通过VS中的NuGet来加载AutoFac,引入成功后引用就会出现Autofac。如图1所示。

图1-1 获取Autofac
示例5中,数据层有两个类,一个是Oracle 一个是SQLSERVER。我们在使用的时候可以选择调用那个数据库。通过Autofac来完成构造函数注入。
示例5
|
/// <summary> /// 数据源操作接口 /// </summary> public interface IDataSource { /// <summary> /// 获取数据 /// </summary> /// <returns></returns> string GetData(); } /// <summary> /// SQLSERVER数据库 /// </summary> public class Sqlserver : IDataSource { public string GetData() { return "通过SQLSERVER获取数据"; } } /// <summary> /// ORACLE数据库 /// </summary> public class Oracle : IDataSource { public string GetData() { return "通过Oracle获取数据"; } } /// <summary> /// 数据源管理类 /// </summary public class DataSourceManager IDataSource _ds; public string GetData() static void Main(string[] args) { //获取Autofac容器构造器 var builder = new ContainerBuilder(); // 注册类型 builder.RegisterType<DataSourceManager>(); // 注册实例(即将SqlServer类型注册为IDataSource的实例 builder.RegisterType<Sqlserver>().As<IDataSource>(); // 由构造器创建Ioc容器 using (var { // 解析实例 var manager = Console.WriteLine(manager.GetData()); Console.ReadLine(); } } |
示例5所示代码展示了Autofac的基本使用,在实际开发中,还有很多其它的用法。
(1) AsImplementedInterfaces (注册多个接口)
在很多情况下,一个类可能实现了多个接口,如果按照实例5的写法,我们需要为每一个接口都注册实例,非常繁琐。这时候就可以使用AsImplementedInterfaces() 方法,可以把一个类注册给它实现的全部接口。代码如下:
builder.RegisterType<Sqlserver>().AsImplementedInterfaces()
(2)利用反射注册
在实际开发中,往往会有很多接口需要注册,这时我们可以通过反射的方式将其全部注册。代码如下:
//加载实现类的程序集
Assembly asm =
Assembly.Load("DAL.BLL");
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();
我们可以在配置文件中将程序集信息在<appSettings>节点中进行配置,来减少对程序集的引用,彻底解除耦合。
(3) PropertiesAutowired (利用属性注入)
上述通过Autofac进行注入都是针对构造函数进行的注册,如果使用属性进行注册需要使用PropertiesAutowired()方法。
//加载实现类的程序集
Assembly asm =
Assembly.Load("DAL.BLL");
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired();
(4)一个接口多个实现
一个接口有多个实现类的情况,如实例5中,SqlServer 和 Oracle 都实现了IDataSource接口,若有同时注册,需要使用Resolve<IEnumerable<IAnimalBLL>>()即可。如实例6所示。
实例6
|
Assembly asm = Assembly.Load("DAL.BLL"); builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces(); using (var container = { IEnumerable<IDataSource> dals = container.Resolve<IEnumerable<IDataSource>>(); foreach(var { Console.WriteLine(dal.GetData()); } Console.ReadLine(); } |
也可以通过Named()方法在指定要想获取的类型。如示例7所示。
示例7
|
//获取Autofac容器构造器 var builder = new ContainerBuilder(); // 注册类型 builder.RegisterType<DataSourceManager>(); // 注册实例 builder.RegisterType<Sqlserver>().Named<IDataSource>("SqlServer"); // 由构造器创建Ioc容器 using { // 解析实例 var manager = Console.WriteLine(manager.GetData()); Console.ReadLine(); } |
1.3.2
通过配置方式使用Autofac
通过配置实现Autofac 需要添加对Autofac.Configuration.dll的引用。
示例8
|
配置文件 <configuration> <configSections> <section name="autofac" </configSections> <autofac defaultAssembly="AutoFacDemo"> <components> <component </components> </autofac> <startup> <supportedRuntime version="v4.0" </startup> </configuration> C#代码 var builder = new builder.RegisterType<DataSourceManager>(); builder.RegisterModule( new |
1.4 在Asp.net
Mvc中使用Autofac
在.net Mvc中使用Autofac,原理和上述讲解一样,区别在于需要通过Nuget多安装一个程序集 Autofac.Mvc5
步骤1
在MVC项目中添加对 Autofac 和 Autofac.Mvc5 的引用。
步骤2
创建配置类。在此我们通过属性注入的方式进行注入,如示例9所示。
示例9
|
public class AutofacConfig { public static void Register() { var builder = new ContainerBuilder(); //加载当前程序集 Assembly controllerAss = //Assembly controllerAss = //注册所有的Controller builder.RegisterControllers(controllerAss).PropertiesAutowired(); //注册数据访问层程序集 Assembly resAss = builder.RegisterTypes(resAss.GetTypes()).AsImplementedInterfaces(); //注册业务层程序集 Assembly bllAss = builder.RegisterTypes(bllAss.GetTypes()).AsImplementedInterfaces(); var container = builder.Build(); //当mvc创建controller对象的时候,都是由AutoFac为我们创建 //Controller对象 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } } |
示例9中对数据层和业务层的注入请根据实际情况进行注册,不是必须的。
步骤3
在Global.asax 的Application_Start()
注册自己的控制器类
protected void
Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
//Autofac配置
AutofacConfig.Register();
}
至此,在MVC中使用 Autofac 的配置步骤完成。
在Controller中的使用如下:
public
class HomeController :Controller
{
public
IDataSource dataSource { get ; set; }
public ActionResult Index( )
{
var data =
dataSource.GetData( );
return
View(data);
}
}
dataSource
属性会被 Autofac 自动实例化。
Asp.net MVC企业级开发(01)---Autofac的更多相关文章
- Asp.net MVC企业级开发(04)---SignalR消息推送
Asp.net SignalR是微软为实现实时通信而开发的一个类库.可以适用于以下场景: 聊天室,如在线客服系统,IM系统等 股票价格实时更新 消息的推送服务 游戏中人物位置的实时推送 SignalR ...
- Asp.net MVC企业级开发(09)---T4模板
T4即为Text Template Transformation Toolkit,一种可以由自己去自定义规则的代码生成器.根据业务模型可生成任何形式的文本文件或供程序调用的字符串 在VS中T4模板是没 ...
- Asp.net MVC企业级开发(02)---Log4net
Log4Net 是用来记录日志的,可以将程序运行过程中的信息输出到一些地方(文件.数据库.EventLog等).日志就是程序的“黑匣子”,可以通过日志查看系统的运行过程,从而发现系统的问题. 日志的作 ...
- Asp.net Mvc模块化开发之分区扩展框架
对于一个企业级项目开发,模块化是非常重要的. 默认Mvc框架的AreaRegistration对模块化开发真的支持很好吗?真的有很多复杂系统在使用默认的分区开发的吗?我相信大部分asp.net的技术团 ...
- ASP.NET MVC企业级项目框架
ASP.NET MVC企业级项目框架 MVC项目搭建笔记---- 项目框架采用ASP.NET MVC+Entity Framwork+Spring.Net等技术搭建,搭建过程内容比较多,结合了抽象工厂 ...
- Easyui + asp.net mvc + sqlite 开发教程(录屏)适合入门
Easyui + asp.net mvc + sqlite 开发教程(录屏)适合入门 第一节: 前言(技术简介) EasyUI 是一套 js的前端框架 利用它可以快速的开发出好看的 前端系统 web ...
- 关于《ASP.NET MVC企业级实战》
大家好,我的书<ASP.NET MVC企业级实战>已经出版啦,感谢大家过去的关注与支持!前言部分,出版的时候漏了部分内容,我这里将其贴出来. 本书提供源码和教学PPT课件!(源码在书中第3 ...
- Asp.net Mvc模块化开发系列(目录)
模块化开发是非常重要的,模块化开发是个系统性问题,为此我觉得有必须要写一个系列的文章才能基本说的清楚 那又为什么要写一个目录呢? 其一.是对我昨天承诺写一个系列新的文章的回应 其二.是先写出一个大纲, ...
- ASP.NET MVC 网站开发总结(三) ——图片截图上传
本着简洁直接,我们就直奔主题吧,这里需要使用到一个网页在线截图插件imgareaselect(请自行下载). 前台页面: <!DOCTYPE html> <html> < ...
随机推荐
- JDBC及C3P0常用类
JDBC(Java Database Connectivity)JAVA数据库连接,它是一套用于执行SQL语句的Java API.JDBC可以通过不同驱动与不同数据库连接,相当于JAVA和数据库之间的 ...
- 远程唤醒、WOL、Magic_Packet【转】
转自:https://www.cnblogs.com/zhuimengle/p/5898830.html 原文:http://blog.csdn.net/flyoxs/article/details/ ...
- 002-OpenStack-认证服务
OpenStack-认证服务 [基于此文章的环境]点我快速打开文章 1.安装和配置 控制节点(controller) 1.1 创库授权 keystone mysql CREATE DATABASE k ...
- PAT 乙级真题 1003 我要通过!题解
1003 我要通过! (20 分) “答案正确”是自动判题系统给出的最令人欢喜的回复.本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案 ...
- pytest中怎么引用前置中的变量
本文主要总结的是pytest中的前置后置怎么返回参数 我们在做自动化的过程中,如果运用的是pytest的话,会遇到怎么使用前置条件中的变量 比如: @pytest.fixture() def init ...
- Springboot jackSon -序列化-详解
在项目中有事需要对值为NULL的对象中Field不做序列化输入配置方式如下: [配置类型]: 源码包中的枚举类: public static enum Include { ALWAYS, NON_NU ...
- Python之flask框架2
Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务.本文参考自Flask官方文档,大部分代码引用自官方文档. 安装flask 首先我们来安装F ...
- CF891B Gluttony
原题链接 DOWNLOAD AS PDF 题目大意 给你一个有\(n\)个元素的数组\(a\),让你构造一个数组\(b\),满足从 \(a\).\(b\)中任选出\(k\)个下标对应的元素,它们的和不 ...
- golang和python互相调用
http://blog.yuanzhaoyi.cn/2018/06/27/golang_python.html python3-ctypes: https://docs.python.org/3.5/ ...
- Apex 中插入更新数据的事件执行顺序
在使用 Apex 代码插入或更新数据的时候,若干事件会被按顺序执行.了解这些顺序可以提高调试程序的效率,也可以避免不必要的错误. 可以参考官方文档. 事件的执行顺序 从数据库中读取要更新的数据记录或初 ...