C# Autofac学习笔记
一、为什么使用autofac?
autofac是.net领域最为流行的ioc框架之一,传说是速度最快的一个。
1.1、性能
有人专门做了测试:
1.2、优点
1)与c#语言联系很紧密。c#里的很多编程方式都可以为autofac使用,例如可以使用lambda表达式注册组件。
2)较低的学习曲线。学习它非常的简单,只要你理解了ioc和di的概念以及在何时需要使用它们。
3)支持json/xml配置。
4)自动装配。
5)与asp.net mvc集成。
6)微软的orchad开源程序使用的就是autofac,可以看出它的方便和强大。
1.3、资源
官方网站:
github网址:https://github.com/autofac/autofac
学习资料:autofac中文文档
二、数据准备
2.1、新建项目
iservice下的接口类:
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; namespace linkto.test.autofac.iservice { /// <summary> /// 动物吠声接口类 /// </summary> public interface ianimalbark { /// <summary> /// 吠叫 /// </summary> void bark(); } }
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; namespace linkto.test.autofac.iservice { /// <summary> /// 动物睡眠接口类 /// </summary> public interface ianimalsleep { /// <summary> /// 睡眠 /// </summary> void sleep(); } }
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; namespace linkto.test.autofac.iservice { /// <summary> /// 学校接口类 /// </summary> public interface ischool { /// <summary> /// 放学 /// </summary> void leaveschool(); } }
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; namespace linkto.test.autofac.iservice { /// <summary> /// 学生接口类 /// </summary> public interface istudent { /// <summary> /// 增加学生 /// </summary> /// <param name="studentid">学生id</param> /// <param name="studentname">学生姓名</param> void add(string studentid, string studentname); } }
service下的接口实现类:
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; using linkto.test.autofac.iservice; namespace linkto.test.autofac.service { /// <summary> /// 猫类 /// </summary> public class cat : ianimalsleep { /// <summary> /// 睡眠 /// </summary> public void sleep() { console.writeline("小猫咪睡着了zz"); } } }
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; using linkto.test.autofac.iservice; namespace linkto.test.autofac.service { /// <summary> /// 狗类 /// </summary> public class dog : ianimalbark, ianimalsleep { /// <summary> /// 吠叫 /// </summary> public void bark() { console.writeline("汪汪汪"); } /// <summary> /// 睡眠 /// </summary> public void sleep() { console.writeline("小狗狗睡着了zz"); } } }
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; using linkto.test.autofac.iservice; namespace linkto.test.autofac.service { /// <summary> /// 学校类 /// </summary> public class school : ischool { /// <summary> /// ianimalbark属性 /// </summary> public ianimalbark animalbark { get; set; } /// <summary> /// 放学 /// </summary> public void leaveschool() { animalbark.bark(); console.writeline("你家的熊孩子放学了⊙o⊙"); } } }
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; using linkto.test.autofac.iservice; namespace linkto.test.autofac.service { /// <summary> /// 学生类 /// </summary> public class student : istudent { /// <summary> /// 无参构造函数 /// </summary> public student() { } /// <summary> /// 有参构造函数 /// </summary> /// <param name="studentid">学生id</param> /// <param name="studentname">学生姓名</param> public student(string studentid, string studentname) { add(studentid, studentname); } /// <summary> /// 增加学生 /// </summary> /// <param name="studentid">学生id</param> /// <param name="studentname">学生姓名</param> public void add(string studentid, string studentname) { console.writeline($"新增的学生是:{studentname}"); } } }
using system; using system.collections.generic; using system.linq; using system.text; using system.threading; using system.threading.tasks; using linkto.test.autofac.iservice; namespace linkto.test.autofac.service { /// <summary> /// 动物摇尾巴 /// </summary> public class animalwagging { /// <summary> /// ianimalbark属性 /// </summary> ianimalbark animalbark; /// <summary> /// 有参构造函数 /// </summary> /// <param name="bark">ianimalbark变量</param> public animalwagging(ianimalbark bark) { animalbark = bark; } /// <summary> /// 摇尾巴 /// </summary> public virtual void wagging() { animalbark.bark(); console.writeline("摇尾巴"); } /// <summary> /// 计数 /// </summary> /// <returns></returns> public static int count() { return 6; } /// <summary> /// 任务 /// </summary> /// <param name="name">动物名称</param> /// <returns></returns> public virtual async task<string> waggingasync(string name) { var result = await task.run(() => count()); return $"{name}摇了{result}下尾巴"; } } }
2.2、autofac安装
client项目右键->管理 nuget 程序包->autofac。
三、ioc-注册
3.1、类型注册
a)类型注册:使用registertype进行注册。
//注册autofac组件 containerbuilder builder = new containerbuilder(); //注册实现类student,当我们请求istudent接口的时候,返回的是类student的对象。 builder.registertype<student>().as<istudent>(); //上面这句也可改成下面这句,这样请求student实现了的任何接口的时候,都会返回student对象。 //builder.registertype<student>().asimplementedinterfaces(); icontainer container = builder.build(); //请求istudent接口 istudent student = container.resolve<istudent>(); student.add("1001", "hello");
b)类型注册(别名):假如一个接口有多个实现类,可以在注册时起别名。
containerbuilder builder = new containerbuilder(); builder.registertype<dog>().named<ianimalsleep>("dog"); builder.registertype<cat>().named<ianimalsleep>("cat"); icontainer container = builder.build(); var dog = container.resolvenamed<ianimalsleep>("dog"); dog.sleep(); var cat = container.resolvenamed<ianimalsleep>("cat"); cat.sleep();
c)类型注册(枚举):假如一个接口有多个实现类,也可以使用枚举的方式注册。
public enum animaltype { dog, cat }
containerbuilder builder = new containerbuilder(); builder.registertype<dog>().keyed<ianimalsleep>(animaltype.dog); builder.registertype<cat>().keyed<ianimalsleep>(animaltype.cat); icontainer container = builder.build(); var dog = container.resolvekeyed<ianimalsleep>(animaltype.dog); dog.sleep(); var cat = container.resolvekeyed<ianimalsleep>(animaltype.cat); cat.sleep();
3.2、实例注册
containerbuilder builder = new containerbuilder(); builder.registerinstance<istudent>(new student()); icontainer container = builder.build(); istudent student = container.resolve<istudent>(); student.add("1001", "hello");
3.3、lambda注册
a)lambda注册
containerbuilder builder = new containerbuilder(); builder.register(c => new student()).as<istudent>(); icontainer container = builder.build(); istudent student = container.resolve<istudent>(); student.add("1001", "hello");
b)lambda注册(namedparameter)
containerbuilder builder = new containerbuilder(); builder.register<ianimalsleep>((c, p) => { var type = p.named<string>("type"); if (type == "dog") { return new dog(); } else { return new cat(); } }).as<ianimalsleep>(); icontainer container = builder.build(); var dog = container.resolve<ianimalsleep>(new namedparameter("type", "dog")); dog.sleep();
3.4、程序集注册
如果有很多接口及实现类,假如觉得这种一一注册很麻烦的话,可以一次性全部注册,当然也可以加筛选条件。
containerbuilder builder = new containerbuilder(); assembly assembly = assembly.load("linkto.test.autofac.service"); //实现类所在的程序集名称 builder.registerassemblytypes(assembly).asimplementedinterfaces(); //常用 //builder.registerassemblytypes(assembly).where(t=>t.name.startswith("s")).asimplementedinterfaces(); //带筛选 //builder.registerassemblytypes(assembly).except<school>().asimplementedinterfaces(); //带筛选 icontainer container = builder.build(); //单实现类的用法 istudent student = container.resolve<istudent>(); student.add("1001", "hello"); //多实现类的用法 ienumerable<ianimalsleep> animals = container.resolve<ienumerable<ianimalsleep>>(); foreach (var item in animals) { item.sleep(); }
3.5、泛型注册
containerbuilder builder = new containerbuilder(); builder.registergeneric(typeof(list<>)).as(typeof(ilist<>)); icontainer container = builder.build(); ilist<string> list = container.resolve<ilist<string>>();
3.6、默认注册
containerbuilder builder = new containerbuilder(); //对于同一个接口,后面注册的实现会覆盖之前的实现。 //如果不想覆盖的话,可以用preserveexistingdefaults,这样会保留原来注册的实现。 builder.registertype<dog>().as<ianimalsleep>(); builder.registertype<cat>().as<ianimalsleep>().preserveexistingdefaults(); //指定为非默认值 icontainer container = builder.build(); var dog = container.resolve<ianimalsleep>(); dog.sleep();
四、ioc-注入
4.1、构造函数注入
containerbuilder builder = new containerbuilder(); builder.registertype<animalwagging>(); builder.registertype<dog>().as<ianimalbark>(); icontainer container = builder.build(); animalwagging animal = container.resolve<animalwagging>(); animal.wagging();
4.2、属性注入
containerbuilder builder = new containerbuilder(); assembly assembly = assembly.load("linkto.test.autofac.service"); //实现类所在的程序集名称 builder.registerassemblytypes(assembly).asimplementedinterfaces().propertiesautowired(); //常用 icontainer container = builder.build(); ischool school = container.resolve<ischool>(); school.leaveschool();
五、ioc-事件
autofac在组件生命周期的不同阶段,共对应了5个事件,执行顺序如下所示:
1.onregistered->2.onpreparing->3.onactivating->4.onactivated->5.onrelease
containerbuilder builder = new containerbuilder(); builder.registertype<student>().as<istudent>() .onregistered(e => console.writeline("onregistered:在注册的时候调用")) .onpreparing(e => console.writeline("onpreparing:在准备创建的时候调用")) .onactivating(e => console.writeline("onactivating:在创建之前调用")) //.onactivating(e => e.replaceinstance(new student("1000", "test"))) .onactivated(e => console.writeline("onactivated:在创建之后调用")) .onrelease(e => console.writeline("onrelease:在释放占用的资源之前调用")); using (icontainer container = builder.build()) { istudent student = container.resolve<istudent>(); student.add("1001", "hello"); }
六、ioc-生命周期
6.1、per dependency
per dependency:为默认的生命周期,也被称为"transient"或"factory",其实就是每次请求都创建一个新的对象。
containerbuilder builder = new containerbuilder(); assembly assembly = assembly.load("linkto.test.autofac.service"); //实现类所在的程序集名称 builder.registerassemblytypes(assembly).asimplementedinterfaces().propertiesautowired().instanceperdependency(); //常用 icontainer container = builder.build(); ischool school1 = container.resolve<ischool>(); ischool school2 = container.resolve<ischool>(); console.writeline(school1.equals(school2));
6.2、single instance
single instance:就是每次都用同一个对象。
containerbuilder builder = new containerbuilder(); assembly assembly = assembly.load("linkto.test.autofac.service"); //实现类所在的程序集名称 builder.registerassemblytypes(assembly).asimplementedinterfaces().propertiesautowired().singleinstance(); //常用 icontainer container = builder.build(); ischool school1 = container.resolve<ischool>(); ischool school2 = container.resolve<ischool>(); console.writeline(referenceequals(school1, school2));
6.3、per lifetime scope
per lifetime scope:同一个lifetime生成的对象是同一个实例。
containerbuilder builder = new containerbuilder(); builder.registertype<school>().as<ischool>().instanceperlifetimescope(); icontainer container = builder.build(); ischool school1 = container.resolve<ischool>(); ischool school2 = container.resolve<ischool>(); console.writeline(school1.equals(school2)); using (ilifetimescope lifetime = container.beginlifetimescope()) { ischool school3 = lifetime.resolve<ischool>(); ischool school4 = lifetime.resolve<ischool>(); console.writeline(school3.equals(school4)); console.writeline(school2.equals(school3)); }
七、ioc-通过配置文件使用autofac
7.1、组件安装
client项目右键->管理 nuget 程序包->autofac.configuration及microsoft.extensions.configuration.xml。
7.2、配置文件
新建一个autofacconfigioc.xml文件,在其属性的复制到输出目录项下选择始终复制。
<?xml version="1.0" encoding="utf-8" ?> <autofac defaultassembly="linkto.test.autofac.iservice"> <!--无注入--> <components name="1001"> <type>linkto.test.autofac.service.student, linkto.test.autofac.service</type> <services name="0" type="linkto.test.autofac.iservice.istudent" /> <injectproperties>true</injectproperties> </components> <components name="1002"> <type>linkto.test.autofac.service.dog, linkto.test.autofac.service</type> <services name="0" type="linkto.test.autofac.iservice.ianimalbark" /> <injectproperties>true</injectproperties> </components> <!--构造函数注入--> <components name="2001"> <type>linkto.test.autofac.service.animalwagging, linkto.test.autofac.service</type> <services name="0" type="linkto.test.autofac.service.animalwagging, linkto.test.autofac.service" /> <injectproperties>true</injectproperties> </components> <!--属性注入--> <components name="3001"> <type>linkto.test.autofac.service.school, linkto.test.autofac.service</type> <services name="0" type="linkto.test.autofac.iservice.ischool" /> <injectproperties>true</injectproperties> </components> </autofac>
7.3、测试代码
//加载配置 containerbuilder builder = new containerbuilder(); var config = new configurationbuilder(); config.addxmlfile("autofacconfigioc.xml"); var module = new configurationmodule(config.build()); builder.registermodule(module); icontainer container = builder.build(); //无注入测试 istudent student = container.resolve<istudent>(); student.add("1002", "world"); //构造函数注入测试 animalwagging animal = container.resolve<animalwagging>(); animal.wagging(); //属性注入测试 ischool school = container.resolve<ischool>(); school.leaveschool();
八、aop
8.1、组件安装
client项目右键->管理 nuget 程序包->autofac.extras.dynamicproxy。
8.2、拉截器
using system; using system.collections.generic; using system.io; using system.linq; using system.reflection; using system.text; using system.threading.tasks; using castle.dynamicproxy; namespace linkto.test.autofac.client { /// <summary> /// 拦截器:需实现iinterceptor接口。 /// </summary> public class calllogger : iinterceptor { private readonly textwriter _output; public calllogger(textwriter output) { _output = output; } /// <summary> /// 拦截方法:打印被拦截的方法--执行前的名称、参数以及执行后的返回结果。 /// </summary> /// <param name="invocation">被拦截方法的信息</param> public void intercept(iinvocation invocation) { //空白行 _output.writeline(); //在下一个拦截器或目标方法处理之前的处理 _output.writeline($"调用方法:{invocation.method.name}"); if (invocation.arguments.length > 0) { _output.writeline($"参数:{string.join(", ", invocation.arguments.select(a => (a ?? "").tostring()).toarray())}"); } //调用下一个拦截器(若存在),直到最终的目标方法(target method)。 invocation.proceed(); //获取被代理方法的返回类型 var returntype = invocation.method.returntype; //异步方法 if (isasyncmethod(invocation.method)) { //task:返回值是固定类型 if (returntype != null && returntype == typeof(task)) { //定义一个异步方法来等待目标方法返回的task async task continuation() => await (task)invocation.returnvalue; //continuation()中并没有使用await,所以continuation()就如同步方法一样是阻塞的。 invocation.returnvalue = continuation(); } //task<t>:返回值是泛型类型 else { //获取被代理方法的返回类型 var returntypet = invocation.method.reflectedtype; if (returntypet != null) { //获取泛型参数集合,集合中的第一个元素等价于typeof(class)。 var resulttype = invocation.method.returntype.getgenericarguments()[0]; //利用反射获得等待返回值的异步方法 methodinfo methodinfo = typeof(calllogger).getmethod("handleasync", bindingflags.public | bindingflags.instance); //调用methodinfo类的makegenericmethod()方法,用获得的类型t(<resulttype>)来重新构造handleasync()方法。 var mi = methodinfo.makegenericmethod(resulttype); //invoke:使用指定参数调用由当前实例表示的方法或构造函数。 invocation.returnvalue = mi.invoke(this, new[] { invocation.returnvalue }); } } var type = invocation.method.returntype; var resultproperty = type.getproperty("result"); if (resultproperty != null) _output.writeline($"方法结果:{resultproperty.getvalue(invocation.returnvalue)}"); } //同步方法 else { if (returntype != null && returntype != typeof(void)) _output.writeline($"方法结果:{invocation.returnvalue}"); } } /// <summary> /// 判断是否异步方法 /// </summary> public static bool isasyncmethod(methodinfo method) { return ( method.returntype == typeof(task) || (method.returntype.isgenerictype && method.returntype.getgenerictypedefinition() == typeof(task<>)) ); } /// <summary> /// 构造等待返回值的异步方法 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="task"></param> /// <returns></returns> public async task<t> handleasync<t>(task<t> task) { var t = await task; return t; } } }
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; using castle.dynamicproxy; namespace linkto.test.autofac.client { public class calltester: iinterceptor { public void intercept(iinvocation invocation) { console.writeline("啥也不干"); invocation.proceed(); console.writeline("也不干啥"); } } }
8.3、测试代码
注意:对于以类方式的注入,autofac interceptor要求类的方法必须为virtual方法。如animalwagging类的wagging()、waggingasync(string name)都加了virtual修饰符。
containerbuilder builder = new containerbuilder(); //注册拦截器 builder.register(c => new calllogger(console.out)); builder.register(c => new calltester()); //动态注入拦截器 //这里定义了两个拦截器,注意它们的顺序。 builder.registertype<student>().as<istudent>().interceptedby(typeof(calllogger), typeof(calltester)).enableinterfaceinterceptors(); //这里定义了一个拦截器 builder.registertype<animalwagging>().interceptedby(typeof(calllogger)).enableclassinterceptors(); builder.registertype<dog>().as<ianimalbark>(); icontainer container = builder.build(); istudent student = container.resolve<istudent>(); student.add("1003", "kobe"); animalwagging animal = container.resolve<animalwagging>(); animal.wagging(); task<string> task = animal.waggingasync("哈士奇"); console.writeline($"{task.result}");
ioc参考自:
https://www.xin3721.com/articlecsharp/c14013.html
https://www.cnblogs.com/googlegetz/p/10218721.html
aop参考自: