热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Autofac的属性注入,IOC的坑

Autofac是一款优秀的IOC的开源工具,完美的适配.Net特性,但是有时候我们想通过属性注入的方式来获取我们注入的对象,对不起,有时候你还真是获取不到,这因为什么呢?1.你对Autofac

 Autofac 是一款优秀的IOC的开源工具,完美的适配.Net特性,但是有时候我们想通过属性注入的方式来获取我们注入的对象,对不起,有时候你还真是获取不到,这因为什么呢?

1.你对Autofac 不太了解,在这个浮躁的社会,没有人会认真的了解每个开源项目,只要求能用就行

2.没有时间了解,你是一个很忙的人,工作很忙,应酬很忙

3.刚开始使用Autofac 还没来得及深入了解就要做项目。

 

不管是什么原因,总之我们注入的属性就是无法直接由autofac 自动注入,或者说我们希望由Autofac自动注入的属性为Null,这可是很让我们纠结的事情。下面我们就来通过一系列我们可能的操作来还原事情的真相。

真相1:通过registerType注册类型,希望通过属性获取注入的类型。

 1   class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             ContainerBuilder builder = new ContainerBuilder();
 6          //   builder.RegisterModule(new LoggingModule());
 7             builder.RegisterType();
 8             builder.RegisterType();
 9             var cOntainer= builder.Build();
10 
11             Test2 test2 = container.Resolve();
12             test2.Show();
13 
14         }
15     }
16 
17     public class Test {
18         public void Show()
19         {
20             Console.WriteLine("FileName");
21         }
22     }
23 
24     public class Test2
25     {
26         public Test Test { get; set; }
27 
28         public void Show()
29         {
30             if (Test != null)
31             {
32                 Test.Show();
33             }
34         }
35     }

 

我们通过RegisterType注入了两个类型Test和Test2,其中Test2中由一个属性为Test类型的Test变量,我们期望Test会自动注入,我们可以直接使用Test.Show方法,但是现实情况是:

我们期望会被Autofac自动注入的属性为Null,我们的期望落空。既然通过RegisterType无法注入,那么通过Register注入呢,是否可行呢?

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             ContainerBuilder builder = new ContainerBuilder();
 6          //   builder.RegisterModule(new LoggingModule());
 7             //builder.RegisterType();
 8             
 9 
10             builder.Register(t => new Test()).As();
11             builder.RegisterType();
12             var cOntainer= builder.Build();
13 
14             Test2 test2 = container.Resolve();
15             test2.Show();
16 
17         }
18     }
19 
20     public class Test {
21         public void Show()
22         {
23             Console.WriteLine("FileName");
24         }
25     }
26 
27     public class Test2
28     {
29         public Test Test { get; set; }
30 
31         public void Show()
32         {
33             if (Test != null)
34             {
35                 Test.Show();
36             }
37         }
38     }

我们通过Register注入一个实例,最后我们的期望还是落空了,还有一种方式就是通过Module进行注册,这种方式还不行,那就说明autofac的属性注入式骗人的(心里想的),我们来通过Module来实现。

真相3:通过module进行注册

  1 class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5             ContainerBuilder builder = new ContainerBuilder();
  6             builder.RegisterModule(new LoggingModule());
  7             //builder.RegisterType();
  8             
  9 
 10             //builder.Register(t => new Test()).As();
 11             //builder.RegisterType();
 12             var cOntainer= builder.Build();
 13 
 14             //Test2 test2 = container.Resolve();
 15             Test2 ee = new Test2();
 16             ee.Show();
 17 
 18         }
 19     }
 20 
 21     public class Test {
 22         public void Show()
 23         {
 24             Console.WriteLine("FileName");
 25         }
 26     }
 27 
 28     public class Test2
 29     {
 30         public Test Test { get; set; }
 31 
 32         public void Show()
 33         {
 34             if (Test != null)
 35             {
 36                 Test.Show();
 37             }
 38         }
 39     }
 40     public class LoggingModule : Module
 41     {
 42         private readonly ConcurrentDictionary<string, Test> _loggerCache;
 43 
 44         public LoggingModule()
 45         {
 46             _loggerCache = new ConcurrentDictionary<string, Test>();
 47         }
 48 
 49         protected override void Load(ContainerBuilder moduleBuilder)
 50         {
 51             // by default, use Coevery's logger that delegates to Castle's logger factory
 52             moduleBuilder.RegisterType().As().InstancePerLifetimeScope();
 53 
 54 
 55             // call CreateLogger in response to the request for an ILogger implementation
 56            // moduleBuilder.Register(CreateLogger).As().InstancePerDependency();
 57 
 58         }
 59 
 60         protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
 61         {
 62             var implementatiOnType= registration.Activator.LimitType;
 63 
 64             // build an array of actions on this type to assign loggers to member properties
 65             var injectors = BuildLoggerInjectors(implementationType).ToArray();
 66 
 67             // if there are no logger properties, there's no reason to hook the activated event
 68             if (!injectors.Any())
 69                 return;
 70 
 71             // otherwise, whan an instance of this component is activated, inject the loggers on the instance
 72             registration.Activated += (s, e) =>
 73             {
 74                 foreach (var injector in injectors)
 75                     injector(e.Context, e.Instance);
 76             };
 77         }
 78 
 79         private IEnumerableobject>> BuildLoggerInjectors(Type componentType)
 80         {
 81             // Look for settable properties of type "ILogger" 
 82             var loggerProperties = componentType
 83                 .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
 84                 .Select(p => new
 85                 {
 86                     PropertyInfo = p,
 87                     p.PropertyType,
 88                     IndexParameters = p.GetIndexParameters(),
 89                     Accessors = p.GetAccessors(false)
 90                 })
 91                 .Where(x => x.PropertyType == typeof(Test)) // must be a logger
 92                 .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer
 93                 .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)); //must have get/set, or only set
 94 
 95             // Return an array of actions that resolve a logger and assign the property
 96             foreach (var entry in loggerProperties)
 97             {
 98                 var propertyInfo = entry.PropertyInfo;
 99 
100                 yield return (ctx, instance) =>
101                 {
102                     string compOnent= componentType.ToString();
103                     var logger = _loggerCache.GetOrAdd(component, key => ctx.Resolve(new TypedParameter(typeof(Type), componentType)));
104                     propertyInfo.SetValue(instance, logger, null);
105                 };
106             }
107         }

 

我们通过Module注册了Test,但是我们通过断点调试可以看到,我们通过属性注入的还是没有得到,还是为Null,这是不是autofac不支持属性注入,我们在心里只骂坑爹啊。

 

但是我们仔细看一下会发现一个问题,我们的Test2 是通过New得到的,而不是通过autofac得到,我们并没有将Test2注入到autofac中,是不是因为这个愿意呢?

我们来尝试一下,这可是我最后的机会了,因为除了这个原因我实在想不出还有什么别的原因。

 

 1  static void Main(string[] args)
 2         {
 3             ContainerBuilder builder = new ContainerBuilder();
 4             builder.RegisterModule(new LoggingModule());
 5             //builder.RegisterType();
 6 
 7 
 8             //builder.Register(t => new Test()).As();
 9             builder.RegisterType();
10             var cOntainer= builder.Build();
11 
12             Test2 test2 = container.Resolve();
13             // Test2 ee = new Test2();
14             test2.Show();
15 
16         }

我们修改了一下代码,将Test2也注入到Autofac中,然后通过autofac的resolve获取,奇迹出现了,我们看到了我们注册的类型,在属性注入得到了我们想要的实例。

这不得不说是一个令我激动的事情,因为这个属性得到的实在是太难,让我尝试了很多种,经历了很多次绝望。

 

所以我发现,如果你要想实现autofac的自动属性注入,由三个步骤,第一个通过module注册你要通过属性获取的类型,第二个,在属性所在的class中,也要注册到autofac中,最后一点,获取属性所在的class的实例必须通过autofac获取,也就是绝对不要通过new来获取,因为autofac的存在就是为了让你在一定程度上减少new的使用。

 

我们使用过autofac的MVC实现,我们发现在controller中可以得到我们的属性值,那是因为controller已经注册到了autofac中,因为肯定有一句builder。registerController的存在。

所在对于想实现autofac自动属性注入的朋友,一定要记得将类型通过module注入到autofac。并且属性所在的类型必须通过autofac获取,因为我们必须让autofac知道类型的存在,才可能会自动注入。

 

这是一篇说明文,简短的说明,希望没有高深的知识点,但是如果你不了解,会花费很长时间才可能查找到错误的地方。应验了那句话,知道了不难,不知道了难上加难。

 

我的座右铭:做架构师,要做牛逼的架构师。

 


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
author-avatar
涐們的故事丘
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有