C# Autofac的具体使用
作者:alxiao
一、为什么使用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、新建项目(例)
项目名称 | 项目说明 | 输出类型 | 引用项目(简写) |
---|---|---|---|
AlXiao.IService | 接口 | 类库 | |
AlXiao.Service | 接口实现 | 类库 | IService |
AlXiao.AdminWebApi | 客户端 | .NETWebApi | IService、Service |
IService下的接口类:
namespace AlXiao.IService { public interface IAccountService { /// <summary> /// 后台程序登陆 /// </summary> /// <param name="UserRequest">后台用户信息</param> /// <returns></returns> Task<ResponseResult> LoginByWeb(tb_adminuser_request UserRequest); } }
Service下的接口实现类:
namespace AlXiao.Service { public class AccountService: IAccountService { /// <summary> /// 后台程序登陆 /// </summary> /// <param name="UserRequest">后台用户信息</param> /// <returns></returns> public async Task<ResponseResult> LoginByWeb(tb_adminuser_request UserRequest) { try { //自己写登录功能 } catch (Exception ex) { } } } }
namespace AlXiao.Service { public class AccountService2: IAccountService { /// <summary> /// 后台程序登陆 /// </summary> /// <param name="UserRequest">后台用户信息</param> /// <returns></returns> public async Task<ResponseResult> LoginByWeb(tb_adminuser_request UserRequest) { try { //自己写登录功能 } catch (Exception ex) { } } } }
2.2、Autofac安装
Client项目右键->管理 NuGet 程序包->Autofac
三、IoC-注册
3.1、类型注册
a)类型注册:使用RegisterType进行注册
/注册Autofac组件 ContainerBuilder builder = new ContainerBuilder; //注册实现类AccountService,当我们请求IAccountService接口的时候,返回的是类Student的对象。 builder.RegisterType<AccountService>.As<IAccountService> ; //上面这句也可改成下面这句,这样请求AccountService实现了的任何接口的时候,都会返回AccountService对象。 //builder.RegisterType<AccountService>.AsImplementedInterfaces(); IContainer container = builder.Build; //请求IAccountService接口 IAccountService baseAccount= container.Resolve<IAccountService> ; baseAccount.LoginByWeb(model);
b)类型注册(别名):假如一个接口有多个实现类,可以在注册时起别名。
ContainerBuilder builder = newContainerBuilder; builder.RegisterType <AccountService>.Named<IAccountService>( "S1"); builder.RegisterType <AccountService2>.Named<IAccountService>( "S2"); IContainer container = builder.Build; var s1= container.ResolveNamed<IAccountService >( "S1"); s1.LoginByWeb(model); var s2 = container.ResolveNamed<IAccountService >( "S2"); s2.LoginByWeb(model);
c)类型注册(枚举):假如一个接口有多个实现类,也可以使用枚举的方式注册。
public enum ServiceType { AccountService, AccountService2 } ContainerBuilder builder = new ContainerBuilder; builder.RegisterType <AccountService>.Keyed<IAccountService> (ServiceType.AccountService); builder.RegisterType <AccountService2>.Keyed<IAccountService> (ServiceType.AccountService2); IContainer container = builder.Build; var s1= container.ResolveKeyed<IAccountService> (ServiceType.AccountService); s1.LoginByWeb(model); var s2= container.ResolveKeyed<IAccountService> (ServiceType.AccountService2); s2.LoginByWeb(model);
3.2、实例注册
ContainerBuilder builder = newContainerBuilder; builder.RegisterInstance <IAccountService>( new AccountService); IContainer container = builder.Build; IAccountService baseAccount= container.Resolve<IAccountService> ; baseAccount.LoginByWeb(model);
3.3、Lambda注册
a)Lambda注册
ContainerBuilder builder = newContainerBuilder; builder.Register(c => new AccountService).As<IAccountService> ; IContainer container = builder.Build; IAccountService baseAccount= container.Resolve<IAccountService> ; baseAccount.LoginByWeb(model);
b)Lambda注册(NamedParameter)
ContainerBuilder builder = newContainerBuilder; builder.Register<IAccountService>((c, p) => { vartype = p.Named<string>("type"); if (type == "S1") { return new AccountService; } else { return new AccountService2; } }).As<IAccountService>; IContainer container = builder.Build; var s1= container.Resolve<IAccountService>(newNamedParameter("type", "S1")); s1.LoginByWeb(model);
3.4、程序集注册
如果有很多接口及实现类,假如觉得这种一一注册很麻烦的话,可以一次性全部注册,当然也可以加筛选条件。
ContainerBuilder builder = newContainerBuilder; Assembly assembly = Assembly.Load( "AlXiao.IService"); //实现类所在的程序集名称 builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces; //常用 //builder.RegisterAssemblyTypes(assembly).Where(t=>t.Name.StartsWith("Service")).AsImplementedInterfaces; //带筛选 //builder.RegisterAssemblyTypes(assembly).Except<School>.AsImplementedInterfaces; //带筛选 IContainer container = builder.Build; //单实现类的用法 IAccountService baseAccount= container.Resolve<IAccountService> ; baseAccount.LoginByWeb(model); //多实现类的用法 IEnumerable<IAccountService> list= container.Resolve<IEnumerable<IAccountService>> ; foreach( var item in list) { item.LoginByWeb(model); }
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<AccountService>.As<IAccountService> ; builder.RegisterType <AccountService1>.As<IAccountService>.PreserveExistingDefaults; //指定为非默认值 IContainer container = builder.Build; var s1= container.Resolve<IAccountService> ; s1.LoginByWeb(model);
四、IoC-注入
4.1、构造函数注入
ContainerBuilder builder = new ContainerBuilder; builder.RegisterType <AccountService> ; builder.RegisterType <AccountService1>.As<IAccountService> ; IContainer container = builder.Build; AccountService s1= container.Resolve<AccountService> ; s1.LoginByWeb(model);
4.2、属性注入
ContainerBuilder builder = new ContainerBuilder; Assembly assembly = Assembly.Load( "AlXiao.IService"); //实现类所在的程序集名称 builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces.PropertiesAutowired; //常用 IContainer container = builder.Build; IAccountService s1= container.Resolve<IAccountService> ; s1.LoginByWeb(model);
五、IOC-事件
Autofac在组件生命周期的不同阶段,共对应了5个事件,执行顺序如下所示:
1.OnRegistered->2.OnPreparing->3.OnActivating->4.OnActivated->5.OnRelease
ContainerBuilder builder = new ContainerBuilder; builder.RegisterType <AccountService>.As<IAccountService> .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) { IAccountService s1= container.Resolve<IAccountService> ; s1.LoginByWeb(model); }
六、IoC-生命周期
6.1、Per Dependency
Per Dependency:为默认的生命周期,也被称为"transient"或"factory",其实就是每次请求都创建一个新的对象。
ContainerBuilder builder = new ContainerBuilder; Assembly assembly = Assembly.Load( "AlXiao.IService"); //实现类所在的程序集名称 builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces.PropertiesAutowired.InstancePerDependency; //常用 IContainer container = builder.Build; IAccountService s1= container.Resolve<IAccountService> ; IAccountService s2 = container.Resolve<IAccountService> ; return s1.Equals(s2);
6.2、Single Instance
Single Instance:就是每次都用同一个对象。
ContainerBuilder builder = new ContainerBuilder; Assembly assembly = Assembly.Load( "AlXiao.IService"); //实现类所在的程序集名称 builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces.PropertiesAutowired.SingleInstance; //常用 IContainer container = builder.Build; IAccountService s1= container.Resolve<IAccountService> ; IAccountService s2= container.Resolve<IAccountService> ; return ReferenceEquals(s1, s2);
6.3、Per Lifetime Scope
Per Lifetime Scope:同一个Lifetime生成的对象是同一个实例。
ContainerBuilder builder = new ContainerBuilder; builder.RegisterType <AccountService>.As<IAccountService> .InstancePerLifetimeScope; IContainer container = builder.Build; IAccountService s1= container.Resolve<IAccountService> ; IAccountService s2 = container.Resolve<IAccountService> ; Console.WriteLine(s1.Equals(s2)); using(ILifetimeScope lifetime = container.BeginLifetimeScope) { IAccountService s3 = lifetime.Resolve<IAccountService> ; IAccountService s4 = lifetime.Resolve<IAccountService> ; Console.WriteLine(s3.Equals(s4)); Console.WriteLine(s2.Equals(s3)); }
七、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="AlXiao.IService"> <!--无注入--> <components name="1001"> <type>AlXiao.IService.AccountService, AlXiao.IService </type> <services name="0"type="AlXiao.IService.IAccountService"/> <injectProperties>true </injectProperties> </components> <components name="1002"> <type>AlXiao.IService.AccountService, AlXiao.IService</type> <services name="0"type="AlXiao.IService.IAccountService2"/> <injectProperties>true </injectProperties> </components> <!--构造函数注入--> <components name="2001"> <type>AlXiao.IService.AccountService, AlXiao.IService</type> <services name="0"type="AlXiao.IService.AccountService, AlXiao.IService"/> <injectProperties>true </injectProperties> </components> <!--属性注入--> <components name="3001"> <type>AlXiao.IService.AccountService, AlXiao.IService</type> <services name="0"type="AlXiao.IService.IAccountService"/> <injectProperties>true </injectProperties> </components> </autofac>
7.3、测试代码
//加载配置 ContainerBuilder builder = new ContainerBuilder; varconfig = new ConfigurationBuilder; config.AddXmlFile( "AutofacConfigIoC.xml"); varmodule = newConfigurationModule(config.Build); builder.RegisterModule(module); IContainer container = builder.Build; //无注入测试 IAccountService s = container.Resolve<IAccountService> ; s.LoginByWeb(model); //构造函数注入测试 AccountService s= container.Resolve<AccountService> ; s.LoginByWeb(model); //属性注入测试 IAccountService s= container.Resolve<IAccountService> ; s.LoginByWeb(model);
八、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 AlXiao.CommonCore.DTO { ///<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; //获取被代理方法的返回类型 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> 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) { vart = awaittask; returnt; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Castle.DynamicProxy; namespace AlXiao.CommonCore.DTO { 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 => newCallLogger(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}");
到此这篇关于C# Autofac的具体使用的文章就介绍到这了,更多相关C# Autofac内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!