ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

最强的 C# Autofac学习笔记

2022-03-28 10:02:15  阅读:240  来源: 互联网

标签:Autofac Resolve container C# builder 笔记 Test usingSystem


一、为什么使用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参考自:

标签:Autofac,Resolve,container,C#,builder,笔记,Test,usingSystem
来源: https://www.cnblogs.com/ypyp123/p/16065716.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有