autofac版本:3.5.2
创建容器
var builder = new ContainerBuilder();
注册方式(这一部分的关注点在于给RegisterType、RegisterAssemblyTypes方法传递的参数,以及可以使用lambda表达式进行筛选)
1、泛型/类型注册,好处是很方便,但是缺点是:所注册的类型需要在当前项目中引用。使用了泛型注册,必须要类型明确。
builder.RegisterType<MSDService>().As<IService>();
2、使用反射+类名字符串进行注册。使用这种注册方式进行注册的类,是可以不需要进行引用的,但是类所在的程序集需要事先被加载进来。(动态加载的时候可以使用这种方式)
builder.RegisterType(System.Type.GetType("MvcApplication1.Services.MSDService"));
3、批量注册指定程序集中的所有非静态类。
builder.RegisterAssemblyTypes(Assembly.Load("MSD.BLL"));
3.1、通常我们并不需要注册一个程序集中所有的类。所以可以使用lambda表达式进行过滤。
Assembly assembly = Assembly.GetExecutingAssembly(); builder.RegisterAssemblyTypes(assembly).Where(x => x.Namespace.Equals("MvcApplication1.Services"));//注册指定命名空间下的所有类型。 builder.RegisterAssemblyTypes(assembly).InNamespaceOf<MSDService>();//注册MSDService类型所在的命名空间下的所有类型。 builder.RegisterAssemblyTypes(assembly).Except<MSDService>();//不注册MSDService类。 builder.RegisterAssemblyTypes(assembly).InNamespace("MvcApplication1.Services");//注册在指定命名空间下的所有类。
4、Lambda注册。1~3所使用的注册方式都是通过构造函数直接new出了对象。如果想在注册之时为类做更多的事情可以通过lambda表达式的注册方式进行注册。
builder.Register(iComponentContext => { MSDService af = new MSDService(); if (af.Guid == null) af.Guid = new System.Guid();//例子举的不好,但是大致的意思就是可以在注册之时,做其他的事情。 return af; });
5、模块注册(这种注册方式最方便,在多人同时协作一个项目的时候,如果使用上面的方式,难免会产生代码冲突,使用这种就可以避免这种情况,只要各自实现IModule接口就可以了)。
builder.RegisterAssemblyModules(assembly);//1、Module实现了IModule接口。2、RegisterAssemblyModules所注册的是实现了IModule接口的类。 builder.RegisterAssemblyModules<MSDService>(assembly);//只注册assembly程序集中继承自MSDService的模块。
解析已注册的类型
IContainer container = builder.Build(); IService msdService = container.Resolve<MSDService>();//如果事先没有对MSDService进行注册,那么Resolve时将会抛出异常。 IService msdService1 = container.ResolveOptional<MSDService>();//如果事先没有对MSDService进行注册,那么将返回一个null值。 IService msdService2 = null; if (container.TryResolve(out msdService2))//类似于tryParse { //如果解析成功 } else { //如果解析失败 }
当一个类有多个构造函数的情况下,autofac会使用哪一个构造函数?
使用尽可能最多参数的那个构造函数。详情:https://www.cnblogs.com/ancupofcoffee/p/5008469.html
可以通过传入指定参数,从而来指定使用哪一种构造函数来生成我们需要的类型。
var obj = container.Resolve<People>(new NamedParameter("guid", Guid.NewGuid()));
NamedParameter 根据参数名称进行匹配。
PositionalParameter 根据参数索引进行匹配,注意:起始索引为0。
TypedParameter 根据类型进行匹配,注意:传入多个相同类型的TypedParameter,所有该类型的参数都将采用第一个TypedParameter的值。
ResolvedParameter 接收两个Func参数,两个Func签名都接收两个相同的参数ParameterInfo和IComponmentContext,第一个参数为参数的信息,第二个参数还是当做IContainer使用就好了。第一个Func的返回值为bool,表明当前这个ResolvedParameter是否使用当前匹配到的参数,如果返回true,则会执行第二个Func;第二个Func返回一个object对象,用于填充构造参数值。
container.Resolve<People>(new ResolvedParameter( x => { }, y => { } ));
注入方式(这部分要关注点是:结合Person和Eating的构造函数或属性,使用不同的方法进行注册,以及在注册时,可能会碰到的问题)
public class Person { public Eating eat = null; //public Person(Eating eat)//如果加上这个构造函数,那么就是属性注入。去掉了,就是自动属性注入 //{ // this.eat = eat; //} public string Name { get; set; } public void Eating() { eat.DoSth(); } }
public class Eating { public void DoSth() { } }
1、属性注入
builder.RegisterType<Models.Eating>();
builder.RegisterType<Models.Person>();
var container1 = builder.Build();
var person = container1.Resolve<Models.Person>();//在person类的构造函数里传入了Eating,但是并不需做其他的操作,只要在之此之前注册Eating就可以了。
2、自动属性注入
builder.RegisterType<Models.Eating>(); builder.RegisterType<Models.Person>().PropertiesAutowired();//使用了PropertiesAutowired方法,只有在autofac中注册过的类型, 才能注入进去。 var container2 = builder.Build(); var person1 = container1.Resolve<Models.Person>();
3、指定属性注入
builder.RegisterType<Models.Person>().WithProperty(new Autofac.Core.NamedPropertyParameter("eat", new Models.Eating())); builder.RegisterType<Models.Person>().WithProperty("eat", new Models.Eating());
4、lambda表达式注入
builder.Register(iComponentContext => { Models.Person p = new Models.Person(); p.eat = new Models.Eating();//人为地注入了一个Eating return p; });
推荐使用不需要传参的构造注入和自动属性注入。不推荐使用方法注册。如果关联类型与注册类型没有继承/实现,那么builder.Build()会报错。
5、当一个类与多个接口进行关联时
builder.RegisterType<C1>().As<I1>().As<I2>().AsSelf();//不使用AsSelf(),如果想获取到一个I3接口的对象,就会抛异常。(只能获取到I1和I2) builder.RegisterType<C1>().AsImplementedInterfaces();
一个接口或类型只能与一个类型进行关联,后面的关联会覆盖前面的关联。
builder.RegisterType<C1>().As<I1>(); // class C1 : I1
builder.RegisterType<C2>().As<I1>(); // class C2 : I1
如果不想让后面的关联覆盖前面的关联,可以像下面这样做
builder.RegisterType<C2>().As<I1>()PreserveExistingDefaults()//这样,C2就不会和I1进行关联了。
可以使用Named <>、Meta<>方法,让一个接口和多个类型进行关联。
最后,autoFac有5个生命周期函数(感觉跟vue或小程序中的差不多)
1、OnRegistered
2、OnPreparing
3、OnActivating:OnActivating事件中推荐的三种操作:1.替换实例对象,或使用代理对象(通过ReplaceInstance方法);2.执行属性注入或方法注入;3.执行其他初始化任务。
4、OnActived:OnActived事件中可以执行一些应用程序级别的任务。
5、OnRelease
builder.RegisterType<A>().OnActivating(e=>{调用一个方法去注册});
var builder = new ContainerBuilder(); builder.RegisterCallback(cr => { // 下面的Registered事件相当类型的OnRegistered事件 cr.Registered += (sender, eventArgs) => { // OnPreparing事件 eventArgs.ComponentRegistration.Preparing += (o, preparingEventArgs) => { }; // OnActivating事件 eventArgs.ComponentRegistration.Activating += (o, activatingEventArgs) => { }; // OnActivated事件 eventArgs.ComponentRegistration.Activated += (o, activatedEventArgs) => { }; }; }); // builder.RegisterType<...>...继续写其他的注册代码
原文地址:https://www.cnblogs.com/ancupofcoffee/category/761892.html