概念
Autofac是一个轻量级的依赖注入的框架,同类型的框架还有Spring.NET,Unity,Castle等;
ContainerBuilder:将组件注册成服务的创建者。
组件:Lambda表达式/一个类型/一个预编译的实例/实例类型所在的程序集
container 容器:通过 ContainerBuilder.Build()创建
获得对象:container.Resolve();
As()方法:可以指定相同的组件暴露成不同的服务。有些没有as就是将本身暴露给用户
组件注册成服务(暴露给用户)
常用注册的方式
1.通过RegisterType
2.同lambda表达式
3.通过实例来注册
4.程序集创建 RegisterAssemblyTypes
5.泛型注册 RegisterGeneric
1 public class 注册方式 2 { 3 /// <summary> 4 /// 1.RegisterType AutoFac能够通过反射检查一个类型,选择一个合适的构造函数,创造这个对象的实例 5 /// </summary> 6 [TestMethod] 7 public void RegisterType() 8 { 9 var builder = new ContainerBuilder(); 10 builder.RegisterType<TestClass>();//方式1 11 builder.RegisterType(typeof(TestClass));//方式2 12 IContainer container = builder.Build(); 13 var class1 = container.Resolve<TestClass>(); 14 Assert.IsTrue(class1 != null); 15 } 16 17 /// <summary> 18 /// 1.RegisterType Named 命名方式注册 19 /// </summary> 20 [TestMethod] 21 public void RegisterType2() 22 { 23 var builder = new ContainerBuilder(); 24 builder.RegisterType<TestClass>().Named<TestClass>("TestClass"); 25 IContainer container = builder.Build(); 26 // var class1 = container.Resolve<TestClass>(); error 27 var class2 = container.ResolveNamed<TestClass>("TestClass"); 28 // Assert.IsTrue(class1 == null); 29 Assert.IsTrue(class2 != null); 30 } 31 32 33 /// <summary> 34 /// 2.Lambda 通过反射的方式实现 35 /// </summary> 36 [TestMethod] 37 public void Lambda() 38 { 39 var builder = new ContainerBuilder(); 40 builder.Register(p=>new TestClass()); 41 IContainer container = builder.Build(); 42 var class1 = container.Resolve<TestClass>(); 43 Assert.IsTrue(class1 != null); 44 } 45 46 47 /// <summary> 48 /// 3.RegisterInstance 实例创建 49 /// </summary> 50 [TestMethod] 51 public void RegisterInstance1() 52 { 53 var builder = new ContainerBuilder(); 54 builder.RegisterInstance<TestClass>(new TestClass()); 55 IContainer container = builder.Build(); 56 var class1 = container.Resolve<TestClass>(); 57 Assert.IsTrue(class1 != null); 58 } 59 60 /// <summary> 61 /// 3.RegisterInstance 将自己系统中原有的单例注册为容器托管的单例 62 /// </summary> 63 [TestMethod] 64 public void RegisterInstance2() 65 { 66 var builder = new ContainerBuilder(); 67 builder.RegisterInstance(TestClass2.GetInstance()).ExternallyOwned(); 68 IContainer container = builder.Build(); 69 var class1 = container.Resolve<TestClass2>(); 70 Assert.IsTrue(class1 != null); 71 } 72 73 74 /// <summary> 75 /// 4.RegisterAssemblyTypes 程序集的创建 76 /// </summary> 77 [TestMethod] 78 public void RegisterAssemblyTypes() 79 { 80 var builder = new ContainerBuilder(); 81 builder.RegisterAssemblyTypes(Assembly.Load("UnitTestProject1")).Where(p => p.Name == "TestClass"); 82 IContainer container = builder.Build(); 83 var class1 = container.Resolve<TestClass>(); 84 Assert.IsTrue(class1 != null); 85 } 86 87 88 89 /// <summary> 90 /// 5.RegisterGeneric 泛型注册 91 /// </summary> 92 [TestMethod] 93 public void RegisterGeneric() 94 { 95 var builder = new ContainerBuilder(); 96 builder.RegisterGeneric(typeof(TestClass3<>)); 97 IContainer container = builder.Build(); 98 var myIntList = container.Resolve<TestClass3<int>>(); 99 Assert.IsTrue(myIntList != null); 100 var myStringList = container.Resolve<TestClass3<string>>(); 101 Assert.IsTrue(myStringList != null); 102 } 103 104 }
注册方式扩展
1.指定构造函数
2.构造函数的参数
3.属性注入
4.方法注入
1 public class 注册方式扩展 2 { 3 /// <summary> 4 /// 构造函数注入 5 /// Autofac默认从容器中选择参数最多的构造函数。如果想要选择一个不同的构造函数,就需要在注册的时候就指定它。 6 /// *可以跟Name或者索引结合起来注册不同的构造函数 7 /// </summary> 8 [TestMethod] 9 public void RegisterType() 10 { 11 var builder = new ContainerBuilder(); 12 builder.RegisterType<TestClass4Paramter1>(); 13 builder.RegisterType<TestClass4Paramter2>(); 14 builder.RegisterType<TestClass4>().UsingConstructor(typeof(TestClass4Paramter1)); 15 // builder.RegisterType<TestClass4>(); 16 IContainer container = builder.Build(); 17 var class1 = container.Resolve<TestClass4>(); 18 Assert.IsTrue(class1.dd == 1); 19 } 20 21 22 23 /// <summary> 24 /// 构造函数参数 WithParameters WithParameter 25 /// </summary> 26 [TestMethod] 27 public void RegisterType2() 28 { 29 var builder = new ContainerBuilder(); 30 //错误情况 多个参数 31 //List<NamedParameter> ListNamedParameter = new List<NamedParameter>() 32 //{ new NamedParameter("paramter1", "dddd") 33 //}; 34 //builder.RegisterType<TestClass5>().WithParameters(ListNamedParameter); 35 36 //错误 37 // builder.RegisterType<TestClass5>().WithParameter(new NamedParameter("paramter1", "dddd")); 38 39 //错误 40 // List<ResolvedParameter> ListNamedParameter = new List<ResolvedParameter>() 41 // { new ResolvedParameter( 42 //(pi, ctx) => pi.ParameterType == typeof(string) && pi.Name == "paramter1", 43 //(pi, ctx) => "sectionName") 44 45 // }; 46 // builder.RegisterType<TestClass5>().WithParameters(ListNamedParameter); 47 48 49 //正确情况 50 //builder.RegisterType<TestClass5>().WithParameter("paramter1", "sectionName"); 51 52 IContainer container = builder.Build(); 53 var class1 = container.Resolve<TestClass5>(); 54 Assert.IsTrue(class1.dd == 1); 55 } 56 57 /// <summary> 58 ///属性注入 59 /// </summary> 60 [TestMethod] 61 public void RegisterType3() 62 { 63 var builder = new ContainerBuilder(); 64 builder.RegisterType<TestClass6>().WithProperty("dd", 1); 65 IContainer container = builder.Build(); 66 var class1 = container.Resolve<TestClass6>(); 67 Assert.IsTrue(class1.dd == 1); 68 } 69 70 /// <summary> 71 ///方法注入 指定注入的方法 72 /// </summary> 73 [TestMethod] 74 public void RegisterType4() 75 { 76 var builder = new ContainerBuilder(); 77 builder.Register(c => 78 { 79 var result = new TestClass7(); 80 result.SetDependency(c.Resolve<ITestClass7>()); 81 return result; 82 }); 83 IContainer container = builder.Build(); 84 var class1 = container.Resolve<TestClass7>(); 85 Assert.IsTrue(class1 != null); 86 } 87 88 89 /// <summary> 90 ///方法注入 使用Activating Handler 指定自身注册完成后触发的事件 91 /// </summary> 92 [TestMethod] 93 public void RegisterType5() 94 { 95 var builder = new ContainerBuilder(); 96 builder.Register<TestClass8>(c => new TestClass8()).OnActivating(e => e.Instance.SetDependency(new TestClass6())); 97 IContainer container = builder.Build(); 98 var class1 = container.Resolve<TestClass8>(); 99 Assert.IsTrue(class1 != null); 100 } 101 102 } 103 104 105 public class TestClass4 106 { 107 public int dd = 0; 108 109 public TestClass4(TestClass4Paramter1 a) 110 { 111 dd = 1; 112 } 113 114 public TestClass4(TestClass4Paramter2 a) 115 { 116 dd = 2; 117 } 118 119 public TestClass4(TestClass4Paramter1 a, TestClass4Paramter2 b) 120 { 121 dd = 12; 122 } 123 124 } 125 126 public class TestClass4Paramter1 127 { 128 129 } 130 131 public class TestClass4Paramter2 132 { 133 134 } 135 136 137 public class TestClass5 138 { 139 public int dd = 0; 140 public TestClass5(string a) 141 { 142 dd = 1; 143 } 144 145 } 146 147 148 public class TestClass6 149 { 150 151 public int dd { get; set; } 152 } 153 154 155 public class TestClass7 156 { 157 private ITestClass7 ITestClass7; 158 public void SetDependency(ITestClass7 ITestClass7) 159 { 160 this.ITestClass7 = ITestClass7; 161 } 162 } 163 164 public interface ITestClass7 165 { 166 167 } 168 169 170 public class TestClass8 171 { 172 173 public void SetDependency(TestClass6 ITestClass6) 174 { 175 var t = ITestClass6.dd; 176 } 177 }
获取服务
常用的获取服务的方式
1 public class 获取服务 2 { 3 /// <summary> 4 /// Resolve 5 /// </summary> 6 [TestMethod] 7 public void Resolve() 8 { 9 var builder = new ContainerBuilder(); 10 builder.RegisterType<TestClass>(); 11 IContainer container = builder.Build(); 12 var class1 = container.Resolve<TestClass>(); 13 Assert.IsTrue(class1 != null); 14 } 15 16 /// <summary> 17 /// ResolveNamed 18 /// </summary> 19 [TestMethod] 20 public void ResolveNamed() 21 { 22 var builder = new ContainerBuilder(); 23 builder.RegisterType<TestClass>().Named<TestClass>("TestClass"); 24 IContainer container = builder.Build(); 25 var class2 = container.ResolveNamed<TestClass>("TestClass"); 26 Assert.IsTrue(class2 != null); 27 } 28 29 /// <summary> 30 /// ResolveKeyed 有Name的方式很方便,但是只支持字符串,但有时候我们可能需要通过其他类型作键。 31 /// </summary> 32 [TestMethod] 33 public void ResolveKeyed() 34 { 35 var builder = new ContainerBuilder(); 36 builder.RegisterType<TestClass>().Keyed<TestClass>(TestState.服务1); 37 IContainer container = builder.Build(); 38 var class2 = container.ResolveKeyed<TestClass>(TestState.服务1); 39 Assert.IsTrue(class2 != null); 40 } 41 42 [TestMethod] 43 public void ResolveIIndex() 44 { 45 var builder = new ContainerBuilder(); 46 builder.RegisterType<TestClass>().Keyed<TestClass>(TestState.服务1); 47 IContainer container = builder.Build(); 48 IIndex<TestState, TestClass> IIndex = container.Resolve<IIndex<TestState, TestClass>>(); 49 TestClass p = IIndex[TestState.服务1]; 50 Assert.IsTrue(p != null); 51 } 52 }
获取服务扩展
当注册或者检索component的时候可以使用参数。
1、传递参数给Resolve
Resolve接受可变参数或IEnumerable<T>传入多个值
using (IContainer container = builder.Build()) { AutoFacManager manager = container.Resolve<AutoFacManager>(new NamedParameter("name", "刘备")); Console.WriteLine(manager.Name); //输出 刘备 manager.Say(); }
此时,AutoFacManager下必须添加如下构造函数
public AutoFacManager(string name,IPerson MyPerson) { Name = name; person = MyPerson; }
2、可用的参数类型
Autofac提供几种不同的参数对应策略:
3、从表达式中使用参数
如果使用表达式注册的方式,可以使用第二个可用的委托参数来获得参数。
builder.Register((c, p) => new AutoFacManager(p.Named<string>("name"), c.Resolve<IPerson>())); builder.RegisterType<Worker>().As<IPerson>(); using (IContainer container = builder.Build()) { AutoFacManager manager = container.Resolve<AutoFacManager>(new NamedParameter("name", "刘备")); Console.WriteLine(manager.Name); //输出刘备 manager.Say(); }
特殊问题
循环依赖
生命周期
生命周期不同阶段使用的事件
主要用于处理一些依赖关系比如在初始化该类之前某个类必须初始化好
或者当前类初始化后其他相关的类必须进行初始化 目前比较不常用
Autofac暴露五个事件接口供实例的按如下顺序调用
builder.RegisterType<Worker>().As<IPerson>() .OnRegistered(e => Console.WriteLine("在注册的时候调用!")) .OnPreparing(e => Console.WriteLine("在准备创建的时候调用!")) .OnActivating(e => Console.WriteLine("在创建之前调用!")) .OnActivated(e => Console.WriteLine("创建之后调用!")) .OnRelease(e => Console.WriteLine("在释放占用的资源之前调用!"));
默认有三种生命周期:
1.Per Dependency:默认的生命周期 每次请求都创建一个新的对象
2.Single Instance:单例模式 每次都用同一个对象
3.Per Lifetime Scope:同一个生命周期生成的对象是同一个实例
1 public class 生命周期 2 { 3 /// <summary> 4 /// 默认生命周期 5 /// </summary> 6 [TestMethod] 7 public void PerDependency() 8 { 9 var builder = new ContainerBuilder(); 10 builder.RegisterType<TestClass>().InstancePerDependency(); 11 IContainer container = builder.Build(); 12 var class1 = container.Resolve<TestClass>(); 13 var class2 = container.Resolve<TestClass>(); 14 Assert.IsFalse(object.ReferenceEquals(class1, class2)); 15 } 16 17 /// <summary> 18 /// 单例 每次都用同一个对象(不同用户使用相同的第一次实例) 19 /// </summary> 20 [TestMethod] 21 public void SingleInstance() 22 { 23 var builder = new ContainerBuilder(); 24 builder.RegisterType<TestClass>().SingleInstance(); 25 26 IContainer container = builder.Build(); 27 var class1 = container.Resolve<TestClass>(); 28 var class2 = container.Resolve<TestClass>(); 29 Assert.IsTrue(object.ReferenceEquals(class1, class2)); 30 } 31 32 33 /// <summary> 34 /// 同一生命周期内使用同一个对象 35 /// </summary> 36 [TestMethod] 37 public void PerLifetimeScope() 38 { 39 var builder = new ContainerBuilder(); 40 builder.RegisterType<TestClass>().InstancePerLifetimeScope(); 41 42 IContainer container = builder.Build(); 43 var class1 = container.Resolve<TestClass>(); 44 var class2 = container.Resolve<TestClass>(); 45 46 ILifetimeScope inner = container.BeginLifetimeScope(); 47 var class3 = inner.Resolve<TestClass>(); 48 var class4 = inner.Resolve<TestClass>(); 49 50 Assert.IsTrue(object.ReferenceEquals(class1, class2)); 51 Assert.IsFalse(object.ReferenceEquals(class1, class3)); 52 Assert.IsTrue(object.ReferenceEquals(class3, class4)); 53 } 54 55 56 }
config配置注入
static void Main(string[] args) { ContainerBuilder builder = new ContainerBuilder(); builder.RegisterType<AutoFacManager>(); builder.RegisterModule(new ConfigurationSettingsReader("autofac")); using (IContainer container = builder.Build()) { AutoFacManager manager = container.Resolve<AutoFacManager>(); manager.Say(); } Console.ReadKey(); }
AutoFac在MVC中的应用
参考资料:http://docs.autofac.org/en/latest/