ASP.NET Core Controller与IOC结合问题整理(3)

ActivatorUtilities类的CreateFactory方法代码虽然比较简单,但是它涉及到调用了其他方法,由于嵌套的比较深代码比较多,而且不是本文讲述的重点,我们就不再这里细说了,我们可以大概的描述一下它的工作流程。

首先在给定的类型里查找到合适的构造函数,这里我们可以理解为查找Controller的构造函数。

然后得到构造信息,并得到构造函数的参数与给定类型参数的对应关系

通过构造信息和构造参数的对应关系,在IServiceProvider得到对应类型的实例为构造函数赋值

最后经过上面的操作通过初始化指定的构造函数来创建给定Controller类型的实例

综上述的相关步骤,我们可以得到一个结论,Controller实例的初始化是通过遍历Controller类型构造函数里的参数,然后根据构造函数每个参数的类型在IServiceProvider查找已经注册到容器中相关的类型实例,最终初始化得到的Controller实例。这就是在IServiceProvider得到需要的依赖关系,然后创建自己的实例,它内部是使用的表达式树来完成的这一切,可以理解为更高效的反射方式。

关于ActivatorUtilities类还包含了其他比较实用的方法,比如CreateInstance方法

public static T CreateInstance<T>(IServiceProvider provider, params object[] parameters)

它可以通过构造注入的方式创建指定类型T的实例,其中构造函数里具体的参数实例是通过在IServiceProvider实例里获取到的,比如我们我们有这么一个类

public class OrderController { private readonly IOrderService _orderService; private readonly IPersonService _personService; public OrderController(IOrderService orderService, IPersonService personService) { _orderService = orderService; _personService = personService; } }

其中它所依赖的IOrderService和IPersonService实例是注册到IOC容器中的

IServiceCollection services = new ServiceCollection() .AddScoped<IPersonService, PersonService>() .AddScoped<IOrderService, OrderService>();

然后你想获取到OrderController的实例,但是它只包含一个有参构造函数,但是构造函数的参数都以注册到IOC容器中。当存在这种场景你便可以通过以下方式得到你想要的类型实例,如下所示

IServiceProvider serviceProvider = services.BuildServiceProvider(); OrderController orderController = ActivatorUtilities.CreateInstance<OrderController>(serviceProvider);

即使你的类型OrderController并没有注册到IOC容器中,但是它的依赖都在容器中,你也可以通过构造注入的方式得到你想要的实例。总的来说ActivatorUtilities里的方法还是比较实用的,有兴趣的同学可以自行尝试一下,也可以通过查看ActivatorUtilities源码的方式了解它的工作原理。

AddControllersAsServices方法

上面我们主要是讲解了默认情况下Controller并不是托管到IOC容器中的,它只是表现出来的让你以为它是在IOC容器中,因为它可以通过构造函数注入相关实例,这主要是ActivatorUtilities类的功劳。说了这么多Controller实例到底可不可以注册到IOC容器中,让它成为真正受到IOC容器的托管者。要解决这个,必须要满足两点条件

首先,需要将Controller注册到IOC容器中,但是仅仅这样还不够,因为Controller是由ControllerFactory创建而来

其次,我们要改造ControllerFactory类中创建Controller实例的地方让它从容器中获取Controller实例,这样就解决了所有的问题

如果我们自己去实现将Controller托管到IOC容器中,就需要满足以上两个操作一个是要将Controller放入容器,然后让创建Controller的地方从IOC容器中直接获取Controller实例。庆幸的是,微软帮我们封装了一个相关的方法,它可以帮我们解决将Controller托管到IOC容器的问题,它的使用方法如下所示

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/bf1ee1456570f5337e46cd2c59e470f6.html