前言
该文仅供学习参考,如有问题请指正。
依赖关系注入 (di) ,是一种软件设计模式,这是一种在类及其依赖项之间实现控制反转 (ioc) 的技术。 .net 中的依赖关系注入是框架的内置部分,与配置、日志记录和选项模式一样。
生命周期
依赖注入有以下三种生命周期
- 瞬时 (transient): 每次从服务容器进行请求时创建的,请求结束后销毁, 这种生存期适合轻量级、 无状态的服务。
- 作用域(scoped):在指定的范围内,第一次请求时会创建一个实例,重复请求时,会返回同一个实例,在处理请求的应用中,请求结束时会释放有作用域的服务。使用 entity framework core 时,默认情况下 adddbcontext 扩展方法使用范围内生存期来注册 dbcontext 类型。
- 单例(singleton):单例生命周期是最长的生命周期,整个应用程序只会创建一个服务实例。这种生命周期适用于那些需要在整个应用程序中共享状态的服务,例如配置(configuration)类、缓存(cache)类等。
用反射实现自动依赖注入
定义三种生命周期的接口类
/// <summary> /// 注入标记,scoped作用域,每次请求时创建一次 /// </summary> public interface iscopeddependency { } /// <summary> /// 注入标记,生命周期singleton,服务第一次请求时创建,后续请求都使用相同的实例 /// </summary> public interface isingletondependency { } /// <summary> /// 注入标记,生命周期transient,每次请求时被创建,适合轻量级服务 /// </summary> public interface itransientdependency { } }
通过getreferencedassemblies实现
getreferencedassemblies该方法只能获取当前程序集所引用的外部程序集,不能获取模式分离/间接引用的程序集
参考地址
/// <summary> /// 动态注册所有服务 /// 约定:interfaces(注入接口), iscopeddependency(生命周期),可以有泛型接口,其它不能再继承。 /// 注意只能注入直接引用的,间接引用的不行 /// </summary> /// <param name="services"></param> /// <returns></returns> public static iservicecollection adddynamicinjectionservice(this iservicecollection services) { //当前程序集 var entryassembly = assembly.getentryassembly(); //获取当前程序集所引用的外部程序集,不能获取模式分离/间接引用的程序集 var types = entryassembly!.getreferencedassemblies() .select(assembly.load)//装载 .concat(new list<assembly>() { entryassembly })//与本程序集合并 .selectmany(x => x.gettypes())//获取所有类 .where(x => !x.isabstract && x.isclass)//排除抽象类 .distinct(); //获取所有继承服务标记的生命周期实现类 var bustypes = types.where(x => x.getinterfaces().any(t => t == typeof(itransientdependency) || t == typeof(iscopeddependency) || t == typeof(isingletondependency)); foreach (var bustype in bustypes) { //过滤泛型接口 var businterface = bustype.getinterfaces() .where(t => t != typeof(itransientdependency) && t != typeof(iscopeddependency) && t != typeof(isingletondependency) && !t.isgenerictype) .firstordefault(); if (businterface == null) continue; if (typeof(itransientdependency).isassignablefrom(bustype)) services.addtransient(businterface, bustype); if (typeof(iscopeddependency).isassignablefrom(bustype)) services.addscoped(businterface, bustype); if (typeof(isingletondependency).isassignablefrom(bustype)) services.addsingleton(businterface, bustype); } return services; }
在program.cs 中添加该服务
builder.services.adddynamicinjectionservice();
加载程序集路径实现
只自动注入该程序集路径下的服务,并且需要约定文件名称
/// <summary> /// 把系统所有business添加到servicecollection /// 加载程序集路径动态注入 /// </summary> /// <param name="services"></param> /// <returns></returns> public static iservicecollection addbusservice(this iservicecollection services) { string rootpath = path.getdirectoryname(assembly.getexecutingassembly().location); var busassembly = assembly.loadfrom(path.combine(rootpath, "wenyan.service.business.dll")); var bustypes = busassembly.gettypes().where(w => w.name.endswith("business")).tolist(); foreach (var bustype in bustypes) { var businterface = bustype.getinterfaces().where(w => w.name.endswith("business")).firstordefault(); if (businterface == null) continue; if (typeof(itransientdependency).isassignablefrom(bustype)) services.addtransient(businterface, bustype); if (typeof(iscopeddependency).isassignablefrom(bustype)) services.addscoped(businterface, bustype); if (typeof(isingletondependency).isassignablefrom(bustype)) services.addsingleton(businterface, bustype); } return services; }
通过依赖注入拓展库:scrutor,使用非常简单,主要通过 fromassemblyof<> 扫描程序集和 addclasses(o) 进行筛选注册
https://github.com/khellang/scrutor 相关详细文档
services.scan(scan => scan // 扫描特定类型所在的程序集,这里是 itransientservice 所在的程序集 .fromassemblyof<itransientservice>() // .addclasses 在上面获取到的程序集中扫描所有公开、非抽象类型 // 之后可以通过委托进行类型筛选,例如下面只扫描实现 itransientservice 的类型 .addclasses(classes => classes.assignableto<itransientservice>()) // 将上面的类型作为它实现的所有接口进行注册 // 如果类型实现了 n 个接口,那么就会有三个独立的注册 .asimplementedinterfaces() // 最后指定注册的生存期,如瞬时,作用域,还是单例 .withtransientlifetime() // 重复上面操作,比如这里扫描 iscopedservice 所在的程序集 .addclasses(classes => classes.assignableto<iscopedservice>()) // 这里和上面不一样的是,这里指定只实现特定的几口,也就是只注册一次 .as<iscopedservice>() // 指定注册的生存期 .withscopedlifetime() // 也支持泛型注册,单个泛型参数 .addclasses(classes => classes.assignableto(typeof(iopengeneric<>))) .asimplementedinterfaces() // 多个泛型参数 .addclasses(classes => classes.assignableto(typeof(iqueryhandler<,>)))
参考链接
https://www.cnblogs.com/saojian/p/17462782.html
https://www.cnblogs.com/qianxingmu/p/13363193.html
https://furion.net/docs/dependency-injection
https://juejin.cn/post/7211158239135383611
到此这篇关于.net webapi中实现自动依赖注入的三种方法的文章就介绍到这了,更多相关.net webapi中实现自动依赖注入的三种方法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论