Asp.net core自定义依赖注入容器,替换自带容器

时间:2024-01-12 16:25:02

依赖注入

在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repository层),而其他层级中也或多或少的使用了依赖注入,在这里不过多的对于依赖注入概念上不进行讲解,如果有不了解的同学,可以在微软官网或者在搜索引擎搜索依赖注入相关概念,本文主要讲解如何在asp.net core中实现自己的依赖注入容器,并且希望更多的同学能够去阅读源码码,因为源码中暴露的一些抽象类或者接口向开发者提供了方便开发者自定义或者拓展的口子。好了,不多啰嗦,我们开始。

First IServiceProviderFactory接口

用过Autofac的同学都知道在asp.net core3版本之后,Autofac的使用方式稍微发生了一些变化,首先需要在Program.cs文件中需要使用Host.UseServiceProviderFactory方法,那实际上这个方法就是让开发者能够去实现自定义的依赖注入容器的一个拓展方法,我们可以查看一下这个方法的定义,注意看有个重点的接口就是IServiceProviderFactory接口,这个接口实际上是指定服务提供者的一个抽象工厂泛型接口,这是实现自定义IOC中最重要的接口之一,也是最开始的一步,实际上,实现自定义依赖注入容器,只需要实现两个接口就可以实现自定义容器,可以看到这个方法有两种参数机制一种是直接传入对应的 实现类,另一种是使用委托的方式去创建对象,并且传入了一个HostBuilderContext的对象,我们会使用这种方式去实现。

Asp.net core自定义依赖注入容器,替换自带容器

Second IServiceProvider接口

Asp.net core自定义依赖注入容器,替换自带容器

Asp.net core自定义依赖注入容器,替换自带容器

Asp.net core自定义依赖注入容器,替换自带容器

我们可以看到这个IServiceProviderFactory接口有两个实现方法,一个是CreateBuilder方法,里面传入IServiceCollection变量,另一个方法是CreateServiceProvider方法,传入我们这个接口指定的容器类的对象,其中IocContainer类不依赖于任何一个抽象,第一个方法的作用就是去构造这个容器的对象,需要返回我们指定的类型的对象,即是这个类是代表着容器,存放服务的,第二个方法是将上面构造的容器对象传入进来,并且返回我们指定的服务提供者,那概念很清晰了,第一个IServiceProviderFactory接口是用来指定我们的容器是哪一个类是我们的容器,以及哪一个是我们的服务提供者,那实际上的IServiceProvider就是第二个重要的一个接口了,这个接口是只有一个方法,GetService方法,参数是一个Type,代表着我们是要去获取哪一个类型的参数,返回值是Object,返回下层依赖者所需要的具体的一个对象。

Asp.net core自定义依赖注入容器,替换自带容器

Three 遵循规则实现自定义容器

那实际上自带的依赖注入容器也是遵循这种规则去实现的,它提供了一个自带的一个ServiceProvider的类去创建对象,那大家都知道启动一个Core的一个程序,自带的一些依赖对象都有一百多个,那大家可能会觉得,让自己去写这种一百多个对象的创建,并且类别还是core的开发者所没有暴露出的类型,创建起来会很麻烦,并且还存在各种依赖,让大家觉得可能自定义依赖注入容器可能很难,实际上,刚开始的时候我也是这么想的,表达式树在我去年十二月份的时候就开始写代码了,只是今年才上传到博客,那实际上,自定义容器我也是去年开始研究的,刚开始也是写了很多判断因为它内部启动的时候大的依赖了两个东西一个是配置的IConfiguration,还有一个就是一个Host的一个类,下面又依赖了很多很多的类,感觉创建起来很麻烦,后来在想到了反射是可以获取程序运行时的元数据并且去构造某个类型,那实际上,我们是可以用反射去实现一种投机取巧的方式去实现自定义依赖注入容器,那就是将启动所依赖服务由自带的ServiceProvider去进行提供和创建,一些项目开发中使用的服务由我们去进行管理,那说到这,已经有很多同学知道了怎么去进行了,我们看代码。

Asp.net core自定义依赖注入容器,替换自带容器

上图中,我们可以看到Provider类是实现了IServiceProvider的接口,并且实现了GetService的方法,可以看到,我使用的方式是去用反射去获取自带的ServiceProvider的构造函数,然后创建这个对象,并且在GetService方法中,首先去判断能否从自带的Provider去获取和创建对象,如果获取不到,那说明是我们项目中所需要的类型,从而使用我们自定义的容器去进行获取对象,默认的获取不到是因为我们在创建ServiceProvider对象的时候传入了IServiceCollection的对象,这里所包含的就是启动Core程序所需要的依赖的集合,这样我们就可以保证,程序启动的时候是可以正常启动的,然后在运行中,请求中所需要的服务类型是由我们自己去创建对象的,所以这样就实现了简单的IOC依赖注入容器,并且替换掉自带的容器。

Four 控制器层的属性注入以及拓展容器实现属性注入和一接口多实现

按照我文章刚开始的时候所说,微软给我们暴露了很多供我们自定义的接口和 抽象类,那如果需要在控制器层实现属性注入那怎么办呢?那实际上还有一个接口,用来让我们去创建控制器,那就是IControllerFactory接口,这个接口有两个方法,一个是CreateController方法和ReleaseController方法,顾名思义就是一个是创建控制器,一个是销毁控制器,那我们可以在第一个方法去实现控制器层的属性注入以及一个接口多实现该怎么去获取的思路,如果是属性注入,我们是需要去创建一个特性用来标记这个属性是用来从容器中获取对象的,我们可以在控制器层或者其他类中使用类似的方法去操作属性注入赋值,如果是一个接口多实现呢,也是需要去定义两个特性,一个特性标记在实现类上面,并且构造函数中有一个string类型的参数,用来标记是在容器中 注入的时候使用某个名称用来标识这个类型,其次在我们进行获取这个类型的时候需要在参数或者属性用我们定义的第二个特性标记这个参数或者属性是从容器中获取的是哪一个名称哪一个类型的对象,这样就可以实现一个属性注入和一个接口多实现的一个操作。

Asp.net core自定义依赖注入容器,替换自带容器

总结

以上是我个人实现自定义IOC的一个解决思路,并且在net core5以及net core6中实现,且5到6实现了无缝升级,没有任何错误,希望能够对各位读者有所帮助。还是希望众多道友能够多解读源码,去查看core框架开发者提供给我们暴露给我们的自定义拓展的一些接口和抽象类。后面我依旧会持续更新core自定义相关的东西,会包括配置还有日志等其他方面的东西,多线程方面的代码已经写完,可以在QQ群6406277群文件中进行查找,也可以查看哪个net群有叫四川观察的,那个就是我。IL后面我也写了很多东西,后续也会一一奉上。在此,谢谢各位看官浏览。

Asp.net core自定义依赖注入容器,替换自带容器