Autofac 的属性注入,IOC的坑
Autofac 是一款优秀的IOC的开源工具,完美的适配.Net特性,但是有时候我们想通过属性注入的方式来获取我们注入的对象,对不起,有时候你还真是获取不到,这因为什么呢?
1.你对Autofac 不太了解,在这个浮躁的社会,没有人会认真的了解每个开源项目,只要求能用就行
2.没有时间了解,你是一个很忙的人,工作很忙,应酬很忙
3.刚开始使用Autofac 还没来得及深入了解就要做项目。
不管是什么原因,总之我们注入的属性就是无法直接由autofac 自动注入,或者说我们希望由Autofac自动注入的属性为Null,这可是很让我们纠结的事情。下面我们就来通过一系列我们可能的操作来还原事情的真相。
真相1:通过registerType注册类型,希望通过属性获取注入的类型。
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
// builder.RegisterModule(new LoggingModule());
builder.RegisterType<Test>();
builder.RegisterType<Test2>();
var container = builder.Build(); Test2 test2 = container.Resolve<Test2>();
test2.Show(); }
} public class Test {
public void Show()
{
Console.WriteLine("FileName");
}
} public class Test2
{
public Test Test { get; set; } public void Show()
{
if (Test != null)
{
Test.Show();
}
}
}
我们通过RegisterType注入了两个类型Test和Test2,其中Test2中由一个属性为Test类型的Test变量,我们期望Test会自动注入,我们可以直接使用Test.Show方法,但是现实情况是:

我们期望会被Autofac自动注入的属性为Null,我们的期望落空。既然通过RegisterType无法注入,那么通过Register注入呢,是否可行呢?
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
// builder.RegisterModule(new LoggingModule());
//builder.RegisterType<Test>(); builder.Register(t => new Test()).As<Test>();
builder.RegisterType<Test2>();
var container = builder.Build(); Test2 test2 = container.Resolve<Test2>();
test2.Show(); }
} public class Test {
public void Show()
{
Console.WriteLine("FileName");
}
} public class Test2
{
public Test Test { get; set; } public void Show()
{
if (Test != null)
{
Test.Show();
}
}
}
我们通过Register注入一个实例,最后我们的期望还是落空了,还有一种方式就是通过Module进行注册,这种方式还不行,那就说明autofac的属性注入式骗人的(心里想的),我们来通过Module来实现。
真相3:通过module进行注册
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new LoggingModule());
//builder.RegisterType<Test>(); //builder.Register(t => new Test()).As<Test>();
//builder.RegisterType<Test2>();
var container = builder.Build(); //Test2 test2 = container.Resolve<Test2>();
Test2 ee = new Test2();
ee.Show(); }
} public class Test {
public void Show()
{
Console.WriteLine("FileName");
}
} public class Test2
{
public Test Test { get; set; } public void Show()
{
if (Test != null)
{
Test.Show();
}
}
}
public class LoggingModule : Module
{
private readonly ConcurrentDictionary<string, Test> _loggerCache; public LoggingModule()
{
_loggerCache = new ConcurrentDictionary<string, Test>();
} protected override void Load(ContainerBuilder moduleBuilder)
{
// by default, use Coevery's logger that delegates to Castle's logger factory
moduleBuilder.RegisterType<Test>().As<Test>().InstancePerLifetimeScope(); // call CreateLogger in response to the request for an ILogger implementation
// moduleBuilder.Register(CreateLogger).As<ILogging.ILogger>().InstancePerDependency(); } protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
var implementationType = registration.Activator.LimitType; // build an array of actions on this type to assign loggers to member properties
var injectors = BuildLoggerInjectors(implementationType).ToArray(); // if there are no logger properties, there's no reason to hook the activated event
if (!injectors.Any())
return; // otherwise, whan an instance of this component is activated, inject the loggers on the instance
registration.Activated += (s, e) =>
{
foreach (var injector in injectors)
injector(e.Context, e.Instance);
};
} private IEnumerable<Action<IComponentContext, object>> BuildLoggerInjectors(Type componentType)
{
// Look for settable properties of type "ILogger"
var loggerProperties = componentType
.GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
.Select(p => new
{
PropertyInfo = p,
p.PropertyType,
IndexParameters = p.GetIndexParameters(),
Accessors = p.GetAccessors(false)
})
.Where(x => x.PropertyType == typeof(Test)) // must be a logger
.Where(x => x.IndexParameters.Count() == ) // must not be an indexer
.Where(x => x.Accessors.Length != || x.Accessors[].ReturnType == typeof(void)); //must have get/set, or only set // Return an array of actions that resolve a logger and assign the property
foreach (var entry in loggerProperties)
{
var propertyInfo = entry.PropertyInfo; yield return (ctx, instance) =>
{
string component = componentType.ToString();
var logger = _loggerCache.GetOrAdd(component, key => ctx.Resolve<Test>(new TypedParameter(typeof(Type), componentType)));
propertyInfo.SetValue(instance, logger, null);
};
}
}
我们通过Module注册了Test,但是我们通过断点调试可以看到,我们通过属性注入的还是没有得到,还是为Null,这是不是autofac不支持属性注入,我们在心里只骂坑爹啊。

但是我们仔细看一下会发现一个问题,我们的Test2 是通过New得到的,而不是通过autofac得到,我们并没有将Test2注入到autofac中,是不是因为这个愿意呢?
我们来尝试一下,这可是我最后的机会了,因为除了这个原因我实在想不出还有什么别的原因。
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new LoggingModule());
//builder.RegisterType<Test>(); //builder.Register(t => new Test()).As<Test>();
builder.RegisterType<Test2>();
var container = builder.Build(); Test2 test2 = container.Resolve<Test2>();
// Test2 ee = new Test2();
test2.Show(); }
我们修改了一下代码,将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知道类型的存在,才可能会自动注入。
这是一篇说明文,简短的说明,希望没有高深的知识点,但是如果你不了解,会花费很长时间才可能查找到错误的地方。应验了那句话,知道了不难,不知道了难上加难。
我的座右铭:做架构师,要做牛逼的架构师。
Autofac 的属性注入,IOC的坑的更多相关文章
- 基于autofac的属性注入
基于autofac的属性注入 什么是属性注入 在了解属性注入之前,要先了解一下DI(Dependency Injection),即依赖注入.在ASP.NET Core里自带了一个IOC容器,而且程序支 ...
- ASP.NET Core中使用Autofac进行属性注入
一些无关紧要的废话: 作为一名双修程序员(自封的),喜欢那种使用Spring的注解形式进行依赖注入或者Unity的特性形式进行依赖注入,当然,形式大同小异,但结果都是一样的,通过属性进行依赖注入. A ...
- Autofac 的属性注入方式
介绍 该篇文章通过一个简单的 ASP.NET MVC 项目进行介绍如何使用 autofac 及 autofac 的 MVC 模块进行依赖注入.注入方式通过构造函数.在编写 aufofac 的依赖注入代 ...
- WebAPI2使用Autofac实现IOC属性注入完美解决方案
一.前言 只要你是.NETer你一定IOC,IOC里面你也会一定知道Autofac,上次说了在MVC5实现属性注入,今天实现在WebApi2实现属性注入,顺便说一下autofac的程序集的注入方式,都 ...
- .NET领域最为流行的IOC框架之一Autofac WebAPI2使用Autofac实现IOC属性注入完美解决方案 AutoFac容器初步
.NET领域最为流行的IOC框架之一Autofac 一.前言 Autofac是.NET领域最为流行的IOC框架之一,微软的Orchad开源程序使用的就是Autofac,Nopcommerce开源程 ...
- ASP.NETCore 3.0 Autofac替换及控制器属性注入及全局容器使用
1.Autofac基础使用 参考: https://www.cnblogs.com/li150dan/p/10071079.html 2.ASP.NETCore 3.0 Autofac 容器替换 需要 ...
- .net core番外第2篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
本篇文章接前一篇,建议可以先看前篇文章,再看本文,会有更好的效果. 前一篇跳转链接:https://www.cnblogs.com/weskynet/p/15046999.html 正文: Autof ...
- spring的属性注入和构造器注入
spring在向IOC容器中注入Bean的时候,有三种注入方式: 属性注入构造器注入工厂方法注入平常中用到的前两种方法较多,下面对前两种方法举例.一.属性注入1.创建一个car类,作为注入的bean ...
- ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)
前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...
随机推荐
- PHP-解析验证码类--学习笔记
1.开始 在 网上看到使用PHP写的ValidateCode生成验证码码类,感觉不错,特拿来分析学习一下. 2.类图 3.验证码类部分代码 3.1 定义变量 //随机因子 private $char ...
- [原]Cachedb 网络模块文档
Cachedb 网络模块文档 整体结构 多路复用 (epoll 模块) 事件驱动 (事件封装) 缓冲管理 (上层buffer管理) 设计思想 层次化的设计,每一个模块只调用上一个模块的接口,并将耦合聚 ...
- Consul-template的简单应用:配置中心,服务发现与健康监测
简介 Consul-template是Consul的一个方扩展工具,通过监听Consul中的数据可以动态修改一些配置文件,大家比较热衷于应用在Nginx,HAProxy上动态配置健康状态下的客户端反向 ...
- Linux命令【第三篇】
执行下面命令时发现提示需要输入密码,请问提示输入的密码是哪个用户的密码. [test@oldboy ~]$ sudo su - oldboy 解答: 输入当前执行命令test账户的密码. 相关说明: ...
- keepalived从机接管后主机恢复不抢占VIP
在lvs+keepalived环境中,为了减小keepalived主从切换带来的意外风险,,设置主机恢复后不抢占VIP.待进行vrrp协议通告备机不可用时切换.主要修改两个地方.(红色部分) 只需修改 ...
- sublime text 3 + python配置,完整搭建及常用插件安装
四年的时间,一直使用EmEditor编辑器进行Python开发,之前是做面向过程,只需要将一个单独的py文件维护好即可,用着也挺顺手,但是最近在做面向对象的开发,不同的py文件中相互关联较多,感觉单纯 ...
- raspberrypi(树莓派)上安装mono和jexus,运行asp.net程序
参考网址: http://www.linuxdot.net/ http://www.cnblogs.com/mayswind/p/3279380.html http://www.raspberrypi ...
- .Net Core 系列:1、环境搭建
前言: 2016年6月28日微软宣布发布 .NET Core 1.0.ASP.NET Core 1.0 和 Entity Framework Core 1.0. .NET Core是微软在两年前发起的 ...
- Ford-Fulkerson 最大流算法
流网络(Flow Networks)指的是一个有向图 G = (V, E),其中每条边 (u, v) ∈ E 均有一非负容量 c(u, v) ≥ 0.如果 (u, v) ∉ E 则可以规定 c(u, ...
- Markdown是怎样接管我的各种的写作工作的
对于一个程序猿来说,没有什么比单纯的写代码更能让人兴奋了.如果能让你像写代码一样写文档,不用再面对那些繁琐的样式,你会怎么看?它就是Markdown!即使博客园已经有不少介绍的文章了,但是我依然还是不 ...