转载 AutoFac常见用法总结
第二节:框架前期准备篇之AutoFac常见用法总结
一. 说在前面的话
本节的内容主要包括:
1. 在使用IOC框架之前的几种创建对象的方式。
2. AutoFac的基本用法和几种生命周期。
3. AutoFac和Asp.Net MVC5进行整合,利用属性的方式进行注入。
事先说明一下本节要用到的实现类和接口类:
(1). Ypf.BLL层中包括:CatBLL、DogBLL、RoleBLL、UserBLL。
1 public class CatBLL : IAnimalBLL
2 {
3 public string Introduce()
4 {
5 return "我是猫";
6 }
7 }
CatBLL
1 public class DogBLL : IAnimalBLL
2 {
3 public string Introduce()
4 {
5 return "我是狗";
6 }
7 }
DogBLL
1 public class RoleBLL : IRoleBLL
2 {
3
4 public IUserBLL userBLL { get; set; }
5
6 /// <summary>
7 /// 展示角色信息
8 /// </summary>
9 /// <returns></returns>
10 public string ShowRoleInfor()
11 {
12 return "我是管理员角色";
13 }
14
15
16 public string ShowDIDemo()
17 {
18 return "哈哈:" + userBLL.GetUserInfor();
19 }
20
21 }
RoleBLL
1 public class UserBLL : IUserBLL,IPeopleBLL
2 {
3 /// <summary>
4 /// 获取用户信息
5 /// </summary>
6 /// <returns></returns>
7 public string GetUserInfor()
8 {
9 return "我是获取用户信息的方法";
10 }
11
12 /// <summary>
13 /// 自我介绍
14 /// </summary>
15 /// <returns></returns>
16 public string Introduce()
17 {
18 return "我是ypf";
19 }
20 }
UserBLL
(2). Ypf.IBLL层包括:IAnimalBLL、IPeopleBLL、IRoleBLL、IUserBLL。
1 public interface IAnimalBLL
2 {
3 string Introduce();
4 }
IAnimalBLL
1 public interface IPeopleBLL
2 {
3 //自我介绍
4 string Introduce();
5 }
IPeopleBLL
1 public interface IRoleBLL
2 {
3 string ShowRoleInfor();
4
5 string ShowDIDemo();
6
7 }
IRoleBLL
1 public interface IUserBLL
2 {
3 string GetUserInfor();
4 }
IUserBLL
二. 引入IOC框架之前的几个写法
1. 最原始的方式直接new(需添加对BLL层的引用)
1 {
2 UserBLL userBll = new UserBLL();
3 var result1 = userBll.GetUserInfor();
4 Console.WriteLine(result1);
5 }
2. 面向接口编程(仍需添加对BLL层的引用)
1 {
2 IUserBLL userBll = new UserBLL();
3 var result1 = userBll.GetUserInfor();
4 Console.WriteLine(result1);
5 }
3. 接口+反射(只需将BLL层的程序集拷贝进来)
1 {
2 Assembly ass = Assembly.Load("Ypf.BLL");
3 Type type = ass.GetType("Ypf.BLL.UserBLL");
4 //调用默认的无参构造函数进行对象的创建
5 object myUserBLL = Activator.CreateInstance(type);
6 IUserBLL userBLL = (IUserBLL)myUserBLL;
7 var result1 = userBLL.GetUserInfor();
8 Console.WriteLine(result1);
9
10 }
4. 手写IOC(反射+简单工厂+配置文件)【需将BLL层的程序集拷贝进来】
配置文件代码:
<appSettings>
<!--直接修改配置文件,可以切换IUserBLL的实现类,发布后可以直接通过改配置文件,代码什么也不用改,体会:反射+面向接口编程-->
<add key="DllName" value="Ypf.BLL"/>
<add key="ClassName" value="Ypf.BLL.UserBLL"/>
</appSettings>
简单工厂代码:
1 /// <summary>
2 /// 简单工厂,隔离对象的创建
3 /// </summary>
4 public class SimpleFactory
5 {
6 private static string DllName = ConfigurationManager.AppSettings["DllName"];
7 private static string ClassName = ConfigurationManager.AppSettings["ClassName"];
8 public static IUserBLL CreateInstance()
9 {
10 Assembly ass = Assembly.Load(DllName);
11 Type type = ass.GetType(ClassName);
12 object obj = Activator.CreateInstance(type);
13 return (IUserBLL)obj;
14 }
15 }
调用代码:
1 {
2 IUserBLL userBLL = SimpleFactory.CreateInstance();
3 var result = userBLL.GetUserInfor();
4 Console.WriteLine(result);
5 }
三. AutoFac常见用法总结
1. 基本用法
同时添加对Ypf.BLL层和Ypf.IBLL层的引用,然后 声明容器→注册实例→解析对象→调用方法、进行测试,代码如下:
1 {
2 ContainerBuilder builder = new ContainerBuilder();
3 //把UserBLL注册为IUserBLL实现类,当请求IUserBLL接口的时候,返回UserBLL对象
4 builder.RegisterType<UserBLL>().As<IUserBLL>();
5 IContainer resolver = builder.Build();
6 IUserBLL userBLL = resolver.Resolve<IUserBLL>();
7 var result1 = userBLL.GetUserInfor();
8 Console.WriteLine(result1);
9 }
评价:这种用法单纯的是为了介绍AutoFac中的几个方法,仅此而已,在实际开发没有这么用的,坑比用法,起不到任何解耦的作用。
2. AsImplementedInterfaces的用法
在很多情况下,一个类可能实现了多个接口, 如果我们通过 builder.RegisterType<xxxBLL>().As<IxxxBLL>(); 这种方式按部就班排着把这个类注册给每个接口,实现几个接口,就要写几行注册代码,很繁琐,我们可以通过 AsImplementedInterfaces() 方法,可以把一个类注册给它实现的全部接口。
这样的话,想用哪个接口,通过Resolve解析即可,代码如下:
1 {
2 ContainerBuilder builder = new ContainerBuilder();
3 //这样请求UserBLL实现的任何接口的时候都会返回 UserBLL 对象。
4 builder.RegisterType<UserBLL>().AsImplementedInterfaces();
5 IContainer resolver = builder.Build();
6 IUserBLL iUserBLL = resolver.Resolve<IUserBLL>();
7 IPeopleBLL iPeopleBLL = resolver.Resolve<IPeopleBLL>();
8
9 var r1 = iUserBLL.GetUserInfor();
10 var r2 = iPeopleBLL.Introduce();
11
12 Console.WriteLine(r1);
13 Console.WriteLine(r2);
14 }
评价:同时添加对Ypf.BLL层和Ypf.IBLL层的引用,这里也是单纯的为了介绍AsImplementedInterfaces()的用法,还是存在实现类的身影,在实际开发中没有这么用的,起不到任何解耦的作用,坑比用法。
3. AutoFac+反射(彻底消灭实现类)
引入反射的背景:前面两种方式都需要添加对Ypf.BLL层的引用,麻烦的要死,根本没有什么改观,还是紧耦合在一起。并且如果有很多接口和实现类的话,用RegisterType一行一行的去写,累个半死,在这种情况下引入反射的概念,简化代码量,代码如下:
1 {
2 ContainerBuilder builder = new ContainerBuilder();
3 //加载实现类的程序集
4 Assembly asm = Assembly.Load("Ypf.BLL");
5 builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();
6 IContainer resolver = builder.Build();
7
8 IUserBLL userBLL = resolver.Resolve<IUserBLL>();
9 IPeopleBLL peopleBLL = resolver.Resolve<IPeopleBLL>();
10 var r1 = userBLL.GetUserInfor();
11 var r2 = peopleBLL.Introduce();
12
13 Console.WriteLine(r1);
14 Console.WriteLine(r2);
15 }
评价:彻底摆脱了实现类的身影,与Ypf.BLL层进行了解耦,只需要添加对Ypf.IBLL层的引用,但需要把Ypf.BLL的程序集拷贝到AutoFacTest项目下。
小小的升级一下:
把反射那个程序集类写到配置文件中,然后在代码中通过读取配置文件进行进一步的反射,代码如下:
1 <appSettings>
2 <add key="DllName" value="Ypf.BLL"/>
3 </appSettings>
1 {
2 ContainerBuilder builder = new ContainerBuilder();
3 //加载实现类的程序集
4 string DllName = ConfigurationManager.AppSettings["DllName"];
5 Assembly asm = Assembly.Load(DllName);
6 builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();
7 IContainer resolver = builder.Build();
8
9 IUserBLL userBLL = resolver.Resolve<IUserBLL>();
10 IPeopleBLL peopleBLL = resolver.Resolve<IPeopleBLL>();
11 var r1 = userBLL.GetUserInfor();
12 var r2 = peopleBLL.Introduce();
13
14 Console.WriteLine(r1);
15 Console.WriteLine(r2);
16 }
4. PropertiesAutowired(属性的自动注入)
背景:一个实现类中定义了其他类型的接口属性,比如RoleBLL中定义IUserBLL的接口属性,而且要对其进行调用, 这个时候就需要通过PropertiesAutowired实现属性的自动注入了。
注:只有通过AutoFac创建的对象才能实现属性的自动注入!! 相关的类、接口要是public类型。
1 public class RoleBLL : IRoleBLL
2 {
3
4 public IUserBLL userBLL { get; set; }
5
6 /// <summary>
7 /// 展示角色信息
8 /// </summary>
9 /// <returns></returns>
10 public string ShowRoleInfor()
11 {
12 return "我是管理员角色";
13 }
14
15
16 public string ShowDIDemo()
17 {
18 return "哈哈:" + userBLL.GetUserInfor();
19 }
20
21
22
23 }
RoleBLL
1 {
2 ContainerBuilder builder = new ContainerBuilder();
3 //加载实现类的程序集
4 Assembly asm = Assembly.Load("Ypf.BLL");
5 builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired();
6 IContainer resolver = builder.Build();
7
8 IRoleBLL iRoleBLL = resolver.Resolve<IRoleBLL>();
9 var r1 = iRoleBLL.ShowDIDemo();
10 Console.WriteLine(r1);
}
下面测试一下不是AutoFac创建的对象能否实现属性的自动注入,新建TempTest类,在里面声明IUserBLL属性,并且在方法中进行调用,然后new一个TempTest对象,对该showMsg方法进行调用,发现报空指针错误,说明userBLL属性为空,没能自动注入。
1 public class TempTest
2 {
3 public IUserBLL userBLL { get; set; }
4
5 public void showMsg()
6 {
7 Console.WriteLine(userBLL.GetUserInfor());
8 }
9 }
1 //测试自己new的对象不能实现属性的自动注入
2 //下面代码报空指针错误
3 {
4 TempTest t = new TempTest();
5 t.showMsg();
6 }
5. 1个接口多个实现类的情况
背景:1个接口有多个实现类的情况(DogBLL 和 CatBLL 都实现了 IAnimalBLL接口)
分析:resolver.Resolve<IAnimalBLL>();只会返回其中一个类的对象
解决方案:如果想返回多个实现类的对象,改成 resolver.Resolve<IEnumerable<IAnimalBLL>>()即可。
1 {
2 ContainerBuilder builder = new ContainerBuilder();
3 //加载实现类的程序集
4 Assembly asm = Assembly.Load("Ypf.BLL");
5 builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired();
6 IContainer resolver = builder.Build();
7
8 //返回 CalBLL 和 DogBLL 中的一个
9 //{
10 // IAnimalBLL iAnimalBLL = resolver.Resolve<IAnimalBLL>();
11 // var r1 = iAnimalBLL.Introduce();
12 // Console.WriteLine(r1);
13 //}
14
15 //如何获取多个呢?
16 {
17 IEnumerable<IAnimalBLL> blls = resolver.Resolve<IEnumerable<IAnimalBLL>>();
18 foreach (IAnimalBLL animalBLL in blls)
19 {
20 Console.WriteLine(animalBLL.GetType());
21 Console.WriteLine(animalBLL.Introduce());
22 }
23 }
24 }
6. AutoFac的几种常见生命周期
1. InstancePerDependency:每次请求 Resovle都返回一个新对象。InstancePerDependency()【这也是默认的创建实例的方式。】
2. SingleInstance: 单例,只有在第一次请求的时候创建 。SingleInstance()
3. InstancePerRequest:ASP.Net MVC 专用,每次http请求内一个对象(也可以理解为一个方法内)。InstancePerRequest() 和 CallContext神似
4. InstancePerLifetimeScope:在一个生命周期域中,每一个依赖或调用创建一个单一的共享的实例,且每一个不同的生命周期域,实例是唯一的,不共享的。
下面测试一下前两种生命周期
情况1
1 {
2 ContainerBuilder builder = new ContainerBuilder();
3 //加载实现类的程序集
4 Assembly asm = Assembly.Load("Ypf.BLL");
5 builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired().InstancePerDependency();
6 IContainer resolver = builder.Build();
7
8 IUserBLL u1 = resolver.Resolve<IUserBLL>();
9 IUserBLL u2 = resolver.Resolve<IUserBLL>();
10
11 Console.WriteLine(object.ReferenceEquals(u1, u2));
12
13 }
结果:False,证明InstancePerDependency 每次都创建一个新对象
情况2
1 {
2 ContainerBuilder builder = new ContainerBuilder();
3 //加载实现类的程序集
4 Assembly asm = Assembly.Load("Ypf.BLL");
5 builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired().SingleInstance();
6 IContainer resolver = builder.Build();
7
8 IUserBLL u1 = resolver.Resolve<IUserBLL>();
9 IUserBLL u2 = resolver.Resolve<IUserBLL>();
10
11 Console.WriteLine(object.ReferenceEquals(u1, u2));
12
13 }
结果:true,证明SingleInstance 每次都返回同一个对象。
四. AutoFac与MVC整合
1. Controller中通过属性注入对象
步骤1:在Ypf.MVC层中添加对Ypf.IBLL层的引用,并将Ypf.BLL的程序集拷贝到 Ypf.MVC中,或者直接改一下Ypf.BLL输出路径。
步骤2:通过Nuget安装程序集 Autofac.Mvc5。
步骤3:在Gloabl 注册 AutoFac代码。
1 public class MvcApplication : System.Web.HttpApplication
2 {
3 protected void Application_Start()
4 {
5 AreaRegistration.RegisterAllAreas();
6 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
7 RouteConfig.RegisterRoutes(RouteTable.Routes);
8 BundleConfig.RegisterBundles(BundleTable.Bundles);
9
10 /***********下面是AutoFac的注册*************/
11 //1. 创建容器
12 var builder = new ContainerBuilder();
13 //2. 把当前程序集中的所有Controller都注册进来
14 builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
15 //3. 把Ypf.BLL中的所有类注册给它的全部实现接口,并且把实现类中的属性也进行注册
16 //{ Assembly asmService = Assembly.Load("Ypf.BLL"); }
17 //PS:这里可以配合配置文件的,将Ypf.BLL写到配置文件中
18 string DllName = ConfigurationManager.AppSettings["DllName"];
19 Assembly asmService = Assembly.Load(DllName);
20 builder.RegisterAssemblyTypes(asmService).Where(t => !t.IsAbstract).AsImplementedInterfaces().PropertiesAutowired();
21 var container = builder.Build();
22 //4. 下面这句话表示当mvc创建controller对象的时候,都是由AutoFac为我们创建Controller对象
23 DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
24
25
26 }
27 }
步骤4:在Controller中进行调用。
2. 普通类中通过代码获取对象
在一个没有通过AutoFac注册的普通类中如何获取接口对象呢,通过DependencyResolver.Current.GetService<IUserBLL>();来获取。
代码如下:
1 public class Utils
2 {
3 public static string Test()
4 {
5 IUserBLL userBLL = DependencyResolver.Current.GetService<IUserBLL>();
6 return userBLL.GetUserInfor();
7 }
8 }
3. 如何在普通类中通过属性的方式注入对象
需要有两个条件:
①: 这个普通类的创建必须在Global中通过AutoFac来进行注册。
②: 获取这个类的时候必须通过 DependencyResolver.Current.GetService<IUserBLL>(); 这种方式来获取。
在Global文件中注册该普通类
该普通类CommonHelp的获取必须通过DependencyResolver.Current.GetService<CommonHelp>();方式来获取。
4. 在单独线程中获取对象
比如在Quartz.Net 中,需要通过下面代码来获取。
详细代码如下:
{
//1.创建作业调度池(Scheduler)
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler(); //2.创建一个具体的作业即job (具体的job需要单独在一个文件中执行)
var job = JobBuilder.Create<HelloJob>().Build(); //3.创建并配置一个触发器即trigger 1s执行一次
var trigger = TriggerBuilder.Create().WithSimpleSchedule(x => x.WithIntervalInSeconds(1)
.RepeatForever()).Build();
//4.将job和trigger加入到作业调度池中
scheduler.ScheduleJob(job, trigger); //5.开启调度
scheduler.Start();
}
1 public class HelloJob:IJob
2 {
3 void IJob.Execute(IJobExecutionContext context)
4 {
5 IUserBLL userBLL;
6 var container = AutofacDependencyResolver.Current.ApplicationContainer;
7 using (container.BeginLifetimeScope())
8 {
9 userBLL = container.Resolve<IUserBLL>();
10 }
11 //下面代码只是测试
12 Console.WriteLine(userBLL.GetUserInfor());
13 }
14 }
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
转载 AutoFac常见用法总结的更多相关文章
- 框架前期准备篇之AutoFac常见用法总结 转载
框架前期准备篇之AutoFac常见用法总结 一. 说在前面的话 凡是大约工作在两年以上的朋友们,或多或少都会接触到一些框架搭建方面的知识,只要一谈到框架搭建这个问题或者最佳用法这个问题,势必会引起一点 ...
- 第二节:框架前期准备篇之AutoFac常见用法总结
一. 说在前面的话 凡是大约工作在两年以上的朋友们,或多或少都会接触到一些框架搭建方面的知识,只要一谈到框架搭建这个问题或者最佳用法这个问题,势必会引起一点点小小的风波,我说我的好,他说他的好,非常容 ...
- [转载]typedef常见用法
注:本文系转载,并修改了一些错误. typedef常见用法 1.常规变量类型定义 例如:typedef unsigned char uchar描述:uchar等价于unsigned char类型定义 ...
- find常见用法
Linux中find常见用法示例 ·find path -option [ -print ] [ -exec -ok command ] {} \; find命令的参数 ...
- DevExpress 控件 GridControl常见用法
刚接触DevExpress第三方控件,把GridControl的常见用法整理一下,以供参考: 说明: gcTest GridControl gvText GridView //隐藏最上面的G ...
- Shell常见用法小记
shell的简单使用 最近发现shell脚本在平常工作中简直算一把瑞士军刀,很多场景下用shell脚本能实现常用的简单需求,而之前都没怎么学习过shell,就趁机把shell相关的语法和常见用法总结了 ...
- JTable常见用法细则+设置某列可编辑+滚动表格
JTable常见用法细则 JTable是Swing编程中很常用的控件,这里总结了一些常用方法以备查阅.欢迎补充,转载请注明作者与出处. 一.创建表格控件的各种方式: 1) 调用无参构造函数. JTa ...
- python map 常见用法
python map 常见用法2017年02月01日 19:32:41 淇怪君 阅读数:548版权声明:欢迎转载,转载请注明出处 https://blog.csdn.net/Tifficial/art ...
- 走入asp.net mvc不归路:[6]linq常见用法
asp.net mvc结合linq,先不说性能问题,对于增删查改的操作还是相当方便的.以下我们就来介绍一下linq在asp.net mvc的Controller中的常见用法. 1 首先来看看整个数据表 ...
随机推荐
- 关于toggle事件委托的处理
当html页面加载后,页面上需要再次动态加载的按钮等事件的绑定,我们有两种处理方案 一.再次加载后进行绑定 二.使用委托进行绑定 而toggle事件是无法直接绑定的,这时可以转化为click的事件,并 ...
- C#编译错误 CS0009:未能打开元数据文件
C#编译错误 CS0009:未能打开元数据文件 编译错误 说明: 在编译向该请求提供服务所需资源的过程中出现错误.请检查下列特定错误详细信息并适当地修改源代码. 编译器错误消息: CS0009: 未能 ...
- SqlServer 登录和卸载
一.数据库简介 SQLServer环境配置 安装好数据库以后怎么启用sa账号来访问数据库. 1.先用windows账号登录数据库. 2.启用windows身份验证方式和sql server身份验证方式 ...
- SQL Server 基本SELECT语句
1.SELECT 和 FROM 语句 SELECT表示执行的是查询,接着需要更知道从哪边查询数据,FROM就是限制读取的数据在哪一个表或哪几个表中,这样就构成了一个基本语句. SELECT * FRO ...
- 在JSP中获取oracle中的时间戳类型的字段并显示
在oracle中有一种特殊的时间显示类型——Timestamp时间戳 通常我们将当前时间转化为时间戳的语法如下: select cast (sysdate as timestamp ) from du ...
- sql server: left join 重复数据
---涂聚文 2017-9-28 SELECT VipExamMailProjectId,VipExamMailStaffID FROM VipExamMailRecord WHERE VipExam ...
- python中文编码&json中文输出问题
python2.x版本的字符编码有时让人很头疼,遇到问题,网上方法可以解决错误,但对原理还是一知半解,本文主要介绍 python 中字符串处理的原理,附带解决 json 文件输出时,显示中文而非 un ...
- HTML5本地存储localStorage与sessionStorage详解
前言 在最近的项目中用到了html5的本地存储,下面总结一下. 1.html5几种存储形式 本地存储(localStorage && sessionStorage) 离线缓存(appl ...
- HTML5是什么,以及优点和缺点
HTML5是超文本标记语言HTML的第五次重大修改 HTML 5 的第一份正式草案已于2008年1月22日公布 2013年5月6日, HTML 5.1正式草案公布 HTML5的优缺点是什么?作为HTM ...
- list中放map的几种方式
package Test; import java.util.*; public class Test { public static void main(String[] args) { //第一种 ...