• 最强的 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、资源

    官方网站: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参考自:

  • 相关阅读:
    Linux Shell编程(3)——运行shell脚本
    Linux Shell编程(2)——第一个shell程序
    Linux Shell编程(1)——shell编程简介
    做“程序员”,不做“码农”,有哪些好办法?
    玩转大数据,顺利渡过34岁裁退危机!
    Google IO 2017为我们带来了什么
    《经验之谈》想要做好SEO推广必知要事,峰任策划告诉您。
    5月17日云栖精选夜读:分布式大数据系统巧实现,全局数据调度管理不再难
    程序员转型发展:拆除这些墙,才会发现更蓝的天空
    敢问路在何方?程序员转行应该卖水果还是卖烧饼
  • 原文地址:https://www.cnblogs.com/ypyp123/p/16065716.html
Copyright © 2020-2023  润新知