第二节:框架前期准备篇之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 }
1 public class dogbll : ianimalbll 2 { 3 public string introduce() 4 { 5 return "我是狗"; 6 } 7 }
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 }
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 }
(2). ypf.ibll层包括:ianimalbll、ipeoplebll、irolebll、iuserbll。
1 public interface ianimalbll 2 { 3 string introduce(); 4 }
1 public interface ipeoplebll 2 { 3 //自我介绍 4 string introduce(); 5 }
1 public interface irolebll 2 { 3 string showroleinfor(); 4 5 string showdidemo(); 6 7 }
1 public interface iuserbll 2 { 3 string getuserinfor(); 4 }
二. 引入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 }
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(姚鹏飞)
- 博客地址 :
- 声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
下一篇: json提取嵌套数据