2020-05-08

C# Autofac学习笔记

C# Autofac学习笔记


    一、为什么使用Autofac?

    Autofac是.NET领域最为流行的IoC框架之一,传说是速度最快的一个。

    1.1、性能

    有人专门做了测试:

    1.2、优点

    1)与C#语言联系很紧密。C#里的很多编程方式都可以为Autofac使用,例如可以使用Lambda表达式注册组件。

    2)较低的学习曲线。学习它非常的简单,只要你理解了IoC和DI的概念以及在何时需要使用它们。

    3)支持JSON/

    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(); }}
IAnimalBark
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(); }}
IAnimalSleep
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(); }}
ISchool
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); }}
IStudent

    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");  } }}
Cat
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");  } }}
Dog
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⊙");  } }}
School
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}");  } }}
Student
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}下尾巴";  } }}
AnimalWagging

    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");
View Code

    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();
View Code

    c)类型注册(枚举):假如一个接口有多个实现类,也可以使用枚举的方式注册。

  public enum AnimalType  {   Dog,   Cat  }
View Code
   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();
View Code

    3.2、实例注册

   ContainerBuilder builder = new ContainerBuilder();   builder.RegisterInstance<IStudent>(new Student());   IContainer container = builder.Build();   IStudent student = container.Resolve<IStudent>();   student.Add("1001", "Hello");
View Code

    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");
View Code

    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();
View Code

    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();   }
View Code

    3.5、泛型注册

   ContainerBuilder builder = new ContainerBuilder();   builder.RegisterGeneric(typeof(List<>)).As(typeof(IList<>));   IContainer container = builder.Build();   IList<string> list = container.Resolve<IList<string>>();
View Code

    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();
View Code

    四、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();
View Code

    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();
View Code

    五、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");   }
View Code

    六、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));
View Code

    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));
View Code

    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));   }
View Code

    七、IoC-通过配置文件使用Autofac

    7.1、组件安装

    Client项目右键->管理 NuGet 程序包->Autofac.Configuration及Microsoft.Extensions.Configuration.

    7.2、配置文件

    新建一个AutofacConfigIoC.

<??><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>
View Code

    7.3、测试代码

   //加载配置   ContainerBuilder builder = new ContainerBuilder();   var config = new ConfigurationBuilder();   config.Add"AutofacConfigIoC.");   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();
View Code

    八、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;  } }}
CallLogger
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("也不干啥");  } }}
CallTester

    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}");
View Code

 

    IoC参考自:

    https://www.xin3721.com/ArticlecSharp/c14013.html

    https://www.cnblogs.com/GoogleGetZ/p/10218721.html

       https://www.cnblogs.com/kissdodog/p/3611799.html

 

    AOP参考自:

    https://www.cnblogs.com/stulzq/p/6880394.html

    https://blog.csdn.net/weixin_38211198/article/details/105925821

    https://blog.csdn.net/q932104843/article/details/97611912


No comments:

Post a Comment