【特别的骚气】asp.net core运行时注入服务,实现类库热插拔
引言
很久之前在群里有看到说asp.net core能不能在运行时注入程序,当时并没有太在意,刚才在某个群里又看到有人再问,core能不能在运行时注入服务,闲来无事,我就研究了一下,其实也比较简单,在之前手写IOC的文章中,我们着重介绍了几个比较重要的接口,这里我们就需要用到那篇文章说到的接口,不明白的同学,传送门在此:Asp.net core自定义依赖注入容器,替换自带容器 - 四处观察 - 博客园 (cnblogs.com)。
IServiceProvider
在这里我们只需要用到这个接口,这个接口有一个GetService的一个方法,我们在创建对象的时候获取对象构造函数依赖的时候可以直接调用这个方法获取参数的对象,那我们都知道这个是IOC容器服务提供者,那它内部肯定是有一个字段或者属性,来存放我们注入或者是系统内部注入的类型的容器,不管是list或者数组,总之肯定是有这么一个东西存在的,所以我在反射的时候发现了在其实现类ServiceProvider中,有一个名为_realizedServices的字段,存放着我们所有注入的服务,看源码我们发现这个字段是一个ConcurrentDictionary类型的一个对象,其中第一个参数为我们注入的对象的类型,第二个参数实际上是一个创建这个Type的一个Func方法,传入的那个ServiceProviderEngineScope方法内部也有一个GetService方法,这样我们传入这个委托的时候,其方法内部我们可以从容器获取我们创建对象的参数,前提是你在运行时注入了你所依赖的参数,否则,肯定是会报错的。
重头戏
在上面看完源码之后,我相信很多同学肯定知道怎么做实现运行时的一个动态注入了,首先我们肯定是需要依赖IServiceProvider接口的实例的,所以我们动态注入的构造函数中肯定需要有这个参数,其次就是我们去GetType,然后GetField,然后在获取到这个Field的具体的对象,然后我们找到ConcurrentDictionary的GetOrAdd方法或者TryAdd,这里我用的是GetOrAdd方法,然后调用,传入对应的参数,就可以完成运行时的动态注入了,可以看到,我们在WeatherForecast接口构造函数中注入了我们依赖的Testdss类型的对象,然后我们构造了一个Func直接添加到了_realizedServices字段中,在第二张图中,我们在构造函数传入了一个IServiceScopeFactory参数去创建一个Scope然后去获取我们注入的Testdss的对象,测试了一下,是没有问题的,同时我在第一次测试的时候是直接传入了Testdss类型的对象进行测试的,也是没有问题的,所以不管是Scope类型的获取或者直接依赖也是没有问题的。
问题
聪明的同学,肯定知道这个其实是存在一个问题的,那就是在默认的注入中,我们对类型的生命周期是可以把控的,可以注入我们需要的单例,或者作用域,在或者是瞬时,但是在这个案例中,我们是没有对这个运行时注入的Testdss做生命周期处理的,其实这个处理起来也简单,我们可以自定定义几个特性,用来标识是单例还是瞬时还是作用域,标记在动态注入的类上,然后在控制动态注入的类中,我们定义容器来存放我们注入的对象,然后在获取的时候,根据类型创建好对象之后,如果是单例的是怎么的逻辑处理,如果是瞬时的又怎么处理,作用域的又怎么处理就行了,就可以实现运行时注入的生命周期的把控。
结语
好了,今天的分享就到此为止了,我是四川观察,喜欢研究这等骚操作,喜欢帮助大家解决问题,欢迎大家骚扰,可以在所在的QQ群中查看有没有叫四川观察的,那就是我;也可以加QQ群6406277,也可以找到我。