一、为什么使用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、资源
官方网站:http://autofac.org/
GitHub网址:https://github.com/autofac/Autofac
学习资料:Autofac中文文档
二、数据准备 2.1、新建项目
IService下的接口类:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
namespaceLinkTo.Test.Autofac.IService
{
///<summary>
///动物吠声接口类
///</summary>
publicinterfaceIAnimalBark
{
///<summary>
///吠叫
///</summary>
voidBark;
}
}
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
namespaceLinkTo.Test.Autofac.IService
{
///<summary>
///动物睡眠接口类
///</summary>
publicinterfaceIAnimalSleep
{
///<summary>
///睡眠
///</summary>
voidSleep;
}
}
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
namespaceLinkTo.Test.Autofac.IService
{
///<summary>
///学校接口类
///</summary>
publicinterfaceISchool
{
///<summary>
///放学
///</summary>
voidLeaveSchool;
}
}
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
namespaceLinkTo.Test.Autofac.IService
{
///<summary>
///学生接口类
///</summary>
publicinterfaceIStudent
{
///<summary>
///增加学生
///</summary>
///<param name="studentID">学生ID</param>
///<param name="studentName">学生姓名</param>
voidAdd( stringstudentID, stringstudentName);
}
}
Service下的接口实现类:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingLinkTo.Test.Autofac.IService;
namespaceLinkTo.Test.Autofac.Service
{
///<summary>
///猫类
///</summary>
publicclassCat : IAnimalSleep
{
///<summary>
///睡眠
///</summary>
publicvoidSleep
{
Console.WriteLine( "小猫咪睡着了zZ");
}
}
}
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingLinkTo.Test.Autofac.IService;
namespaceLinkTo.Test.Autofac.Service
{
///<summary>
///狗类
///</summary>
publicclassDog : IAnimalBark, IAnimalSleep
{
///<summary>
///吠叫
///</summary>
publicvoidBark
{
Console.WriteLine( "汪汪汪");
}
///<summary>
///睡眠
///</summary>
publicvoidSleep
{
Console.WriteLine( "小狗狗睡着了zZ");
}
}
}
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingLinkTo.Test.Autofac.IService;
namespaceLinkTo.Test.Autofac.Service
{
///<summary>
///学校类
///</summary>
publicclassSchool : ISchool
{
///<summary>
///IAnimalBark属性
///</summary>
publicIAnimalBark AnimalBark { get; set; }
///<summary>
///放学
///</summary>
publicvoidLeaveSchool
{
AnimalBark.Bark;
Console.WriteLine( "你家的熊孩子放学了⊙o⊙");
}
}
}
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingLinkTo.Test.Autofac.IService;
namespaceLinkTo.Test.Autofac.Service
{
///<summary>
///学生类
///</summary>
publicclassStudent : IStudent
{
///<summary>
///无参构造函数
///</summary>
publicStudent
{ }
///<summary>
///有参构造函数
///</summary>
///<param name="studentID">学生ID</param>
///<param name="studentName">学生姓名</param>
publicStudent( stringstudentID, stringstudentName)
{
Add(studentID, studentName);
}
///<summary>
///增加学生
///</summary>
///<param name="studentID">学生ID</param>
///<param name="studentName">学生姓名</param>
publicvoidAdd( stringstudentID, stringstudentName)
{
Console.WriteLine($ "新增的学生是:{studentName}");
}
}
}
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading;
usingSystem.Threading.Tasks;
usingLinkTo.Test.Autofac.IService;
namespaceLinkTo.Test.Autofac.Service
{
///<summary>
///动物摇尾巴
///</summary>
publicclassAnimalWagging
{
///<summary>
///IAnimalBark属性
///</summary>
IAnimalBark animalBark;
///<summary>
///有参构造函数
///</summary>
///<param name="bark">IAnimalBark变量</param>
publicAnimalWagging(IAnimalBark bark)
{
animalBark = bark;
}
///<summary>
///摇尾巴
///</summary>
publicvirtualvoidWagging
{
animalBark.Bark;
Console.WriteLine( "摇尾巴");
}
///<summary>
///计数
///</summary>
///<returns></returns>
publicstaticintCount
{
return6;
}
///<summary>
///任务
///</summary>
///<param name="name">动物名称</param>
///<returns></returns>
publicvirtualasyncTask< string> WaggingAsync( stringname)
{
varresult = awaitTask.Run( => Count);
return$ "{name}摇了{result}下尾巴";
}
}
}
2.2、Autofac安装
Client项目右键->管理 NuGet 程序包->Autofac。
三、IoC-注册 3.1、类型注册
a)类型注册:使用RegisterType进行注册。
//注册Autofac组件
ContainerBuilder builder = newContainerBuilder;
//注册实现类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 = newContainerBuilder;
builder.RegisterType <Dog>.Named<IAnimalSleep>( "Dog");
builder.RegisterType <Cat>.Named<IAnimalSleep>( "Cat");
IContainer container = builder.Build;
vardog = container.ResolveNamed<IAnimalSleep>( "Dog");
dog.Sleep;
varcat = container.ResolveNamed<IAnimalSleep>( "Cat");
cat.Sleep;
c)类型注册(枚举):假如一个接口有多个实现类,也可以使用枚举的方式注册。
publicenumAnimalType
{
Dog,
Cat
}
ContainerBuilder builder = newContainerBuilder;
builder.RegisterType <Dog>.Keyed<IAnimalSleep> (AnimalType.Dog);
builder.RegisterType <Cat>.Keyed<IAnimalSleep> (AnimalType.Cat);
IContainer container = builder.Build;
vardog = container.ResolveKeyed<IAnimalSleep> (AnimalType.Dog);
dog.Sleep;
varcat = container.ResolveKeyed<IAnimalSleep> (AnimalType.Cat);
cat.Sleep;
3.2、实例注册 ContainerBuilder builder = newContainerBuilder;
builder.RegisterInstance <IStudent>( newStudent);
IContainer container = builder.Build;
IStudent student = container.Resolve<IStudent> ;
student.Add( "1001", "Hello"); 3.3、Lambda注册
a)Lambda注册
ContainerBuilder builder = newContainerBuilder;
builder.Register(c => newStudent).As<IStudent> ;
IContainer container = builder.Build;
IStudent student = container.Resolve<IStudent> ;
student.Add( "1001", "Hello");
b)Lambda注册(NamedParameter)
ContainerBuilder builder = newContainerBuilder;
builder.Register <IAnimalSleep>((c, p) =>
{
vartype = p.Named< string>( "type");
if(type == "Dog")
{
returnnewDog;
}
else
{
returnnewCat;
}
}).As <IAnimalSleep> ;
IContainer container = builder.Build;
vardog = container.Resolve<IAnimalSleep>( newNamedParameter( "type", "Dog"));
dog.Sleep;
3.4、程序集注册
如果有很多接口及实现类,假如觉得这种一一注册很麻烦的话,可以一次性全部注册,当然也可以加筛选条件。
ContainerBuilder builder = newContainerBuilder;
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( varitem inanimals)
{
item.Sleep;
}
3.5、泛型注册 ContainerBuilder builder = newContainerBuilder;
builder.RegisterGeneric( typeof(List<>)).As( typeof(IList<> ));
IContainer container = builder.Build;
IList < string> list = container.Resolve<IList< string>>; 3.6、默认注册
ContainerBuilder builder = newContainerBuilder;
//对于同一个接口,后面注册的实现会覆盖之前的实现。
//如果不想覆盖的话,可以用PreserveExistingDefaults,这样会保留原来注册的实现。
builder.RegisterType<Dog>.As<IAnimalSleep> ;
builder.RegisterType <Cat>.As<IAnimalSleep>.PreserveExistingDefaults; //指定为非默认值
IContainer container = builder.Build;
vardog = container.Resolve<IAnimalSleep> ;
dog.Sleep;
四、IoC-注入 4.1、构造函数注入
ContainerBuilder builder = newContainerBuilder;
builder.RegisterType <AnimalWagging> ;
builder.RegisterType <Dog>.As<IAnimalBark> ;
IContainer container = builder.Build;
AnimalWagging animal = container.Resolve<AnimalWagging> ;
animal.Wagging;
4.2、属性注入
ContainerBuilder builder = newContainerBuilder;
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 = newContainerBuilder;
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 = newContainerBuilder;
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 = newContainerBuilder;
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 = newContainerBuilder;
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 = newContainerBuilder;
varconfig = newConfigurationBuilder;
config.AddXmlFile( "AutofacConfigIoC.xml");
varmodule = newConfigurationModule(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、拉截器
usingSystem;
usingSystem.Collections.Generic;
usingSystem.IO;
usingSystem.Linq;
usingSystem.Reflection;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingCastle.DynamicProxy;
namespaceLinkTo.Test.Autofac.Client
{
///<summary>
///拦截器:需实现IInterceptor接口。
///</summary>
publicclassCallLogger : IInterceptor
{
privatereadonlyTextWriter _output;
publicCallLogger(TextWriter output)
{
_output = output;
}
///<summary>
///拦截方法:打印被拦截的方法--执行前的名称、参数以及执行后的返回结果。
///</summary>
///<param name="invocation">被拦截方法的信息</param>
publicvoidIntercept(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;
//获取被代理方法的返回类型
varreturnType = invocation.Method.ReturnType;
//异步方法
if(IsAsyncMethod(invocation.Method))
{
//Task:返回值是固定类型
if(returnType != null&& returnType == typeof(Task))
{
//定义一个异步方法来等待目标方法返回的Task
asyncTask Continuation => await(Task)invocation.ReturnValue;
//Continuation中并没有使用await,所以Continuation就如同步方法一样是阻塞的。
invocation.ReturnValue = Continuation;
}
//Task<T>:返回值是泛型类型
else
{
//获取被代理方法的返回类型
varreturnTypeT = invocation.Method.ReflectedType;
if(returnTypeT != null)
{
//获取泛型参数集合,集合中的第一个元素等价于typeof(Class)。
varresultType = invocation.Method.ReturnType.GetGenericArguments[ 0];
//利用反射获得等待返回值的异步方法
MethodInfo methodInfo = typeof(CallLogger).GetMethod( "HandleAsync", BindingFlags.Public | BindingFlags.Instance);
//调用methodInfo类的MakeGenericMethod方法,用获得的类型T(<resultType>)来重新构造HandleAsync方法。
varmi = methodInfo.MakeGenericMethod(resultType);
//Invoke:使用指定参数调用由当前实例表示的方法或构造函数。
invocation.ReturnValue = mi.Invoke( this, new[] { invocation.ReturnValue });
}
}
vartype = invocation.Method.ReturnType;
varresultProperty = 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>
publicstaticboolIsAsyncMethod(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>
publicasyncTask<T> HandleAsync<T>(Task<T> task)
{
vart = awaittask;
returnt;
}
}
}
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingCastle.DynamicProxy;
namespaceLinkTo.Test.Autofac.Client
{
publicclassCallTester: IInterceptor
{
publicvoidIntercept(IInvocation invocation)
{
Console.WriteLine( "啥也不干");
invocation.Proceed;
Console.WriteLine( "也不干啥");
}
}
}
8.3、测试代码
注意:对于以类方式的注入,Autofac Interceptor要求类的方法必须为virtual方法。如AnimalWagging类的Wagging、WaggingAsync(string name)都加了virtual修饰符。
ContainerBuilder builder = newContainerBuilder;
//注册拦截器
builder.Register(c => newCallLogger(Console.Out));
builder.Register(c => newCallTester);
//动态注入拦截器
//这里定义了两个拦截器,注意它们的顺序。
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
http://niuyi.github.io/blog/2012/04/06/autofac-by-unit-test/
AOP参考自: