4. ASP.NET Core默认服务
之前讲了中心件,实际上一个中心件要正常进行工作,通常须要许多的服务配合进行,而中心件中的服务自然也是通过 Ioc 容器进行注册和注入的。前面也讲到,按照约定中心件的封装一样平常会提供一个 User{Middleware} 的扩展方法给用户利用,而服务注册中也有一个类似的约定,一样平常会有一个 Add{Services} 的扩展方法。
比方一个WebApi项目中,对于控制器路由终结点中心件的配置利用:
- builder.Services.AddControllers();
- var app = builder.Build();
- app.MapControllers();
复制代码 这也是我们在日常开发中可以学习的方式,随着业务增长,须要依靠注入的服务也越来越多,我们可以根据业务模块,通过扩展方法将相应模块的服务注入注册进行封装,定名为 Add{Services},更加清楚明了地对我们的业务进行封装。
.NET Core 框架下默认提供250个以上的的服务,包罗 ASP.NET Core MVC、EF Core 等等,固然这些服务很多不会默认就注入到容器中,我们在新建一个项目的时候,不同项目框架的模板会帮我们默认配置好一些最基本的必须的服务,其他的服务我们可以根据自己的须要进行利用。
5. 依靠注入配置变形
随着业务的增长,我们项目工作中的类型、服务越来越多,而每一个服务的依靠注入关系都须要在入口文件通过Service.Add{xxx}方法去进行注册,这将是非常麻烦的,入口文件须要频仍改动,而且代码组织管理也会变得麻烦,非常不优雅。
在许多框架中会对这种通过 Service.Add{xxx} 在代码中显式注册依靠注入关系的方式进行变形,有的可以通过配置文件进行注册,比方 Java Spring 框架就有如许大量的配置文件,有的可以通过接口进行默认注册,有的通过特性进行默认注册。
这里轻微简单介绍一下依靠注入默认注册的原理,其实也就是通过反射的一些本领,再加上一些约定好的规则而已。
首先须要三个生命周期接口,如下,这三个接口没有内容,仅仅只是作为标志而已。
- public interface ISingleton
- {
- }
- public interface IScoped
- {
- }
- public interface ITransient
- {
- }
复制代码 之后须要一个扩展方法,如下:
- namespace Microsoft.Extensions.DependencyInjection
- {
- public static class ServiceCollectionDependencyExtensions
- {
- public static IServiceCollection AddAutoInject<T>(this IServiceCollection services)
- {
- var register = new ServiceRegister();
- register.AddAssembly(services, typeof(T).Assembly);
- return services;
- }
- }
- }
复制代码 这个扩展方法中调用了注册器,往容器中注入服务,实现如下:
- public class ServiceRegister
- {
- public void AddAssembly(IServiceCollection services, Assembly assembly)
- {
- // 查找程序中的类型
- var types = assembly.GetTypes().Where(t => t != null && t.IsClass && !t.IsAbstract && !t.IsGenericType);
- // 遍历每一个类检查释放满足约定的规则
- foreach (var type in types)
- {
- AddType(services, type);
- }
- }
- /// <summary>
- /// 添加当前类型的依赖注入关系
- /// </summary>
- /// <param name="services"></param>
- /// <param name="type"></param>
- public void AddType(IServiceCollection services, Type type)
- {
- var lifetime = GetLifetimeOrNull(type);
- if (lifetime == null)
- {
- return;
- }
- var exposeServices = ExposeService(type);
- foreach (var serviceType in exposeServices)
- {
- var serviceDescriptor = new ServiceDescriptor(serviceType, type, lifetime.Value);
- services.Add(serviceDescriptor);
- }
- }
- /// <summary>
- /// 根据标记接口确定生命周期,如果没有添加标记接口的,则不会被自动注册到容器
- /// </summary>
- /// <param name="type"></param>
- /// <returns></returns>
- public ServiceLifetime? GetLifetimeOrNull(Type type)
- {
- if (typeof(ISingleton).IsAssignableFrom(type))
- {
- return ServiceLifetime.Singleton;
- }
- if(typeof(IScoped).IsAssignableFrom(type))
- {
- return ServiceLifetime.Scoped;
- }
- if(typeof(ITransient).IsAssignableFrom(type))
- {
- return ServiceLifetime.Transient;
- }
- return null;
- }
- /// <summary>
- /// 根据约定的规则查找当前类对于的服务类型
- /// 通过接口实现的方式,查找当前类实现的接口,如果一个接口名称去除了 "I" 之后与当前类的后半段一样,
- /// 则当前类应该被注册为这个接口的服务。
- /// </summary>
- /// <param name="type"></param>
- /// <returns></returns>
- public IList<Type> ExposeService(Type type)
- {
- var serviceTypes = new List<Type>();
- var interfaces = type.GetInterfaces();
- foreach (var interfacesType in interfaces)
- {
- var interfaceName = interfacesType.Name;
- if (interfaceName.StartsWith("I"))
- {
- interfaceName = interfaceName.Substring(1);
- }
- if (type.Name.EndsWith(interfaceName))
- {
- serviceTypes.Add(interfacesType);
- }
- }
- return serviceTypes;
- }
- }
复制代码 整体的逻辑就是查找遍历程序会合的全部类型,并通过判别类型是否实现之前定好的三个生命周期接口,从而确定类型是否须要自动注册到容器中,假如须要再根据约定好的规则获取须要注册的服务类型,并且构建服务形貌器,再将其添加到容器中。
之后在入口文件中如许利用:
- builder.Services.AddAutoInject<Program>();
复制代码 而须要自动注入的服务只要多实现一个标志接口即可:
- public class Rabbit : IRabbit, ITransient
- {
- }
复制代码 以上重要介绍一下依靠注入自动化注册的思路和基本实现,代码只是一个基本的演示,比较简单,很多细节也没有在这里表现,但是核心的思路是和ABP框架中的自动注入的方式一样的,有兴趣详细了解一下ABP中的依靠注入的机制的童鞋,可以看一下我其他的文章: ABP 依靠注入(1)
参考文章:
ASP.NET Core 依靠注入 | Microsoft Learn
明白ASP.NET Core - 依靠注入(Dependency Injection)
ASP.NET Core 系列:
目录:ASP.NET Core 系列总结
上一篇:ASP.NET Core — 依靠注入(三)
下一篇:ASP.NET Core — 配置系统之配置读取
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |