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> < ...
随机推荐
- 5.如何基于 dubbo 进行服务治理、服务降级、失败重试以及超时重试?
作者:中华石杉 面试题 如何基于 dubbo 进行服务治理.服务降级.失败重试以及超时重试? 面试官心理分析 服务治理,这个问题如果问你,其实就是看看你有没有服务治理的思想,因为这个是做过复杂微服务的 ...
- 简单使用:SpringBoot整合Redis
1.导入依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- centos7 apache 配置ssl
因为小程序后台服务器需要是https的,所以这两天赶紧百度了一波什么是https以及怎么将服务器升级为https.虽然网上教程很多但因具体环境可能有差异导致一路遇坑,摸爬滚打了两天终于弄好了.遂记下一 ...
- 通过premake生成vs工程文件
visual studio的工程视图,在引用外部目录时非常麻烦,这时候可以使用premake一键生成工程文件,自动配置好工程的各种属性,还有目录的组织结构. 示例:如下是一个c++的外部目录结构,我们 ...
- 简易解说拉格朗日对偶(Lagrange duality)(转载)
转载自https://www.cnblogs.com/90zeng/p/Lagrange_duality.html,本人觉得讲的非常好! 1.原始问题 假设是定义在上的连续可微函数(为什么要求连续可微 ...
- requests---HTTPS请求
做过接口测试的都会发现,现在的接口都是HTTPS协议了,今天就写一篇如何通过request发送https请求,如果不是很了解HTTP协议的同学可以看下我的另外一篇博客什么是HTTP 什么是HTTPS ...
- 分母为0的坑(float)
分母不能为0 对于int 类型,如果分母为0,在程序运行时,会报错. 而对于float 类型,如果分母为0,则不会报错,而是会返回一个infinity(无穷大),也就是NAN. 因为除一个无穷小的数, ...
- IDEA结合Maven的profile构建不同开发环境(SpringBoot)
一.概述 在开发过程中,我们的项目会存在不同的开发环境,比如开发环境.生产环境.测试环境,而我们的项目在不同的环境中有些配置也是不一样的,比如数据源配置.日志文件配置等,假如我们每次将软件部署到不同的 ...
- 201871010133-赵永军《面向对象程序设计(java)》第十三周学习总结
201871010133-赵永军<面向对象程序设计(java)>第十三周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...
- zz深度学习中的注意力模型
中间表示: C -> C1.C2.C3 i:target -> IT j: source -> JS sim(Query, Key) -> Value Key:h_j,类似某种 ...