一、前言

  在之前的文章【ASP.NET Core 整合Autofac和Castle实现自动AOP拦截】中,我们讲过除了ASP.NETCore自带的IOC容器外,如何使用Autofac来接管IServiceProvider进行依赖注入。

  最近老有想法在ASP.NET Mvc Core中实现Controller的属性值的依赖注入,但是找遍了Microsoft.Extensions.DependencyInjection类库也没找到对应的方法,而且查看源代码之后发现其都是针对构造器进行依赖注入的,并没有对属性或字段进行依赖注入。

  官方给我们的两种获取依赖注入结果的方法:ActivatorUtilities.CreateInstanceIServiceProvider.GetService,这两个方法的区别,这里我就不详细阐述了,有兴趣的朋友可以自己去查看一下这两个类的源代码:ServiceProviderActivatorUtilities,但总得来说两个方法在创建对象时都没有注入属性值。

  简单的调用这两个方法:首先在Startup.ConfigureServices函数中,添加语句services.AddTransient<IUser, MyUser>();

  . IUser user = ActivatorUtilities.CreateInstance(serviceProvider, typeof(IUser));
  . IUser user = serviceProvider.GetService(typeof(IUser))

  这两个函数的返回结果都是一样的,而且如果MyUser的构造器中有接口类型的话,两个方法也同样会进行依赖注入,但是都不会对创建出的对象属性进行注入。但是这两个方法还是有原理上的不同,ActivatorUtilities是通过构建ExpressionTree的方式对类型的构造器进行构造并创建出对象的,并使用IServiceProvider注入的构造器;而ServiceProvider则是完全通过依赖注入的生命周期的CallSite,对类型进行递归创建对象的。

  如果非要说那个方法更好的话,其实显而易见IServiceProvider是一个接口,而ActivatorUtilities是一组方法,而且ASP.NET Core中的DI生命周期中到处都是ServiceProvider的身影,它的扩展能力无需解释。

二、使用Autofac

  其使这个例子中使用Autofac就是为了偷懒而已,主要是autofac已经支持属性的依赖注入了。但是确无法直接使用,通过研究ASP.NET Core MVC的源代码,我找到了解决方法,并借助Autofac来完成Controller属性的依赖注入操作。

  在上一篇介绍Autofac文章中提到过,Autofac是通过修改Startup.ConfigureServices函数的返回值,及返回值由void修改成IServiceProvider来完成的。

public IServiceProvider ConfigureServices(IServiceCollection services)
{
var builder = new ContainerBuilder();
services.AddMvc();
builder.Populate(services);
this.ApplicationContainer = builder.Build();
return new AutofacServiceProvider(this.ApplicationContainer);
}

  通过返回AutofacServiceProvider类型的IServiceProvider,Autofac就通过装饰模式就接管了ServiceProvider。但是只是接管IServiceProvider以后,我们会发现这并不能注入属性值,经过对ASP.NET Core源代码的研究,整理了如下思路:

  1.找到所有Controller的类型

var manager = new ApplicationPartManager();
manager.ApplicationParts.Add(new AssemblyPart(assembly));
manager.FeatureProviders.Add(new ControllerFeatureProvider());
var feature = new ControllerFeature();
manager.PopulateFeature(feature);

  通过ApplicationPartManager,ASP.NET Core管理着所有程序组件,这里的AssemblyPart是一个程序集组件,也就是说ASP.NET Core MVC会在这个程序集中查找Controller类型或其它使用的类型。我们也可以通过这个方法来添加一个程序集,用于把MVC的项目拆成两个独立的项目,比如Controller项目和View项目等。

  ControllerFeatureProvider这个类看名字就知道它用于是查找Controller类型的。我们来摘一段它的代码看看:

public void PopulateFeature(IEnumerable<ApplicationPart> parts,ControllerFeature feature)
{
foreach (var part in parts.OfType<IApplicationPartTypeProvider>())
{
foreach (var type in part.Types)
{
if (IsController(type) &&!feature.Controllers.Contains(type))
{
feature.Controllers.Add(type);
}
}
}
}

  2.通过Autofac对Controller类型进行注册

 builder.RegisterTypes(feature.Controllers.Select(ti => ti.AsType()).ToArray()).PropertiesAutowired();

  Autofac中通过对ControllerFeature中的Controller进行IOC注册,并使用PropertiesAutowired开启属性注入。

  3.修改默认的Controller创建者,使用Autofac的ServiceProvider完成Controller的创建工作。

  这也是最重要的一步,通过查看源代码ASP.NET Core默认使用DefaultControllerActivator类对Controller进行创建工作;但是找到这个类的Create函数发布它其实调用的是ActivatorUtilities来创建对象的。前面也说过这个的话,在创建类型对象时,IServiceProvdier只负责对构造器中的参数进行查找注入,创建对象的操作还是由ActivatorUtilities来create出来的,这样也就没用利用上autofac替换的ServiceProvider,也就是说ActivatorUtilities并没有扩展点来使用我们提供的方法进行替换,所以才造成了无法注入的问题。

  下面代码添加到Services.AddMvc();之前,如下:

 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

  其实就是用ServiceBasedControllerActivator来替换默认的DefaultControllerActivator ;来看看它的源代码吧,一下就明白了:

 public object Create(ControllerContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
} var controllerType = actionContext.ActionDescriptor.ControllerTypeInfo.AsType();
return actionContext.HttpContext.RequestServices.GetRequiredService(controllerType);
}

  这里的RequestServices就是IServiceProvider所以都懂的,这里使用的已经是咱们替换过用Provider了。

  最后再加一个Demo,看看属性User是不是被注入值了:

 public class HomeController : Controller
{
public IUserManager User { set; get; } public IActionResult Index()
{
User.Register("hello");
return View();
}
}

三、最后

  ASP.NET Core的源代码实在是学习的好材料,每一个组件都是一个扩展,每一个组件都有一组小部件;真正的组件式开发!  

  

  DEMO的Git地址:https://github.com/maxzhang1985/AutofacCastle.AspNetCore.Demo

  GitHub:https://github.com/maxzhang1985/YOYOFx  如果觉还可以请Star下, 欢迎一起交流。

  .NET Core 和 YOYOFx 的交流群: 214741894

  

查看.NET Core源代码通过Autofac实现依赖注入到Controller属性的更多相关文章

  1. NET Core源代码通过Autofac实现依赖注入

    查看.NET Core源代码通过Autofac实现依赖注入到Controller属性   阅读目录 一.前言 二.使用Autofac 三.最后 回到目录 一.前言 在之前的文章[ASP.NET Cor ...

  2. 如何在.NET Core控制台程序中使用依赖注入

    背景介绍 依赖注入(Dependency Injection), 是面向对象编程中的一种设计原则,可以用来减低代码之间的耦合度.在.NET Core MVC中 我们可以在Startup.cs文件的Co ...

  3. 在.NET Core控制台程序中使用依赖注入

    之前都是在ASP.NET Core中使用依赖注入(Dependency Injection),昨天遇到一个场景需要在.NET Core控制台程序中使用依赖注入,由于对.NET Core中的依赖注入机制 ...

  4. NopCommerce使用Autofac实现依赖注入

    NopCommerce的依赖注入是用的AutoFac组件,这个组件在nuget可以获取,而IOC反转控制常见的实现手段之一就是DI依赖注入,而依赖注入的方式通常有:接口注入.Setter注入和构造函数 ...

  5. .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]

    原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...

  6. .NET CORE学习笔记系列(2)——依赖注入[7]: .NET Core DI框架[服务注册]

    原文https://www.cnblogs.com/artech/p/net-core-di-07.html 包含服务注册信息的IServiceCollection对象最终被用来创建作为DI容器的IS ...

  7. .NET CORE学习笔记系列(2)——依赖注入[6]: .NET Core DI框架[编程体验]

    原文https://www.cnblogs.com/artech/p/net-core-di-06.html 毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动 ...

  8. .NET CORE学习笔记系列(2)——依赖注入[5]: 创建一个简易版的DI框架[下篇]

    为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在上篇中我们介绍了Cat的基本编程模式,接下来我们就来聊聊Cat的 ...

  9. .NET CORE学习笔记系列(2)——依赖注入【3】依赖注入模式

    原文:https://www.cnblogs.com/artech/p/net-core-di-03.html IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架中以实现对流 ...

随机推荐

  1. SVN Server for Migration

    SVN Server: http://mxsuse01/svn/repos/erp/Oracle_EMS Report SVN (Put to SVN Sort) 1. *.RDF 2. *CP.LD ...

  2. C语言的傻瓜式随笔(一):嵌套循环-程序结构

    循环语句的嵌套 一个循环结构内可以含有另一个循环,称为循环嵌套,又称多重循环.常用的循环嵌套是二重循环,外层循环称为外循环,内层循环称为内循环. ---------不知道哪来的基础概念 这是本宝宝的第 ...

  3. 非常全面的SQL Server巡检脚本来自sqlskills团队的Glenn Berry 大牛

    非常全面的SQL Server巡检脚本来自sqlskills团队的Glenn Berry 大牛 Glenn Berry 大牛会对这个脚本持续更新 -- SQL Server 2012 Diagnost ...

  4. 进一步封装highchart,打造自己的图表插件:jHighChart.js

    Highcharts 是一个用纯JavaScript编写的一个图表库, 能够很简单便捷的在web网站或是web应用程序添加有交互性的图表.支持的图表类型有曲线图.区域图.柱状图.饼状图.散状点图和综合 ...

  5. python实现grep

    import sys import os import re def usage(): print "[Usage]: python grep.py filename grepString. ...

  6. 利用Hexo搭建个人博客-博客初始化篇

    上一篇博文 <利用Hexo搭建个人博客-环境搭建篇> 中,我们讲解了利用Hexo搭建个人博客应该要配置哪些环境.相信大家已经迫不及待的想要知道接下来应该要怎么把自己的博客搭起来了,下面,让 ...

  7. Azure PowerShell (7) 使用CSV文件批量设置Virtual Machine Endpoint

    <Windows Azure Platform 系列文章目录> 请注意: - Azure不支持增加Endpoint Range - 最多可以增加Endpoint数量为150 http:// ...

  8. Azure PowerShell (11) 使用自定义虚拟机镜像模板,创建Azure虚拟机并绑定公网IP(VIP)和内网IP(DIP)

    <Windows Azure Platform 系列文章目录> 前提要求: 1.假设笔者捕获一个Azure虚拟机模板,命名为leistorage 关于Azure虚拟机模板,请参考下图: 2 ...

  9. yar框架使用笔记

    Yar是什么 Yar是并行的RPC框架(Concurrent RPC framework),Laruence开发. 安装 下载地址:http://pecl.php.net/package/yar wi ...

  10. 谈谈php里的DAO Model AR

    这次要谈的3个关键字:DAO.Model.AR,是我们在做web应用时常见的几个概念,也被称作设计模式(design pattern),先简单看看它们的全拼和中文: DAO:Data Access O ...