.NET Core中实现自动注入、批量注入
- NetCore
- 2022/1/27 14:59:00
- 人已阅读
简介我们在使用AddScoped、AddTransient、AddSingleton这类方法的时候很是麻烦。我们每增加一个接口以及其实现的时候,是不是需要在这里硬编码注册一行代码呢?项目小还好,但当我们的项目变得庞大之后,这里的依赖注入怎么来维护呢?
在网上翻了半天,看了很多方法,其实现代码感觉都很不优雅,想想还是自己写一个比较实用吧,我们只需按照一个规定来定义和实现接口。应用程序就能自动扫描并注册这些程序集中的接口和对应实现类,完成依赖注入的自动注册,具体的实现可以通过接口或特性来实现,具体实现如下:
第一步:创建如下这样空接口,用于标记需要注入
public interface IDependency { } /// <summary> /// 实现该接口将自动注册到Ioc容器,生命周期为每次请求创建一个实例 /// </summary> public interface IScopeDependency: IDependency { } /// <summary> /// 实现该接口将自动注册到Ioc容器,生命周期为单例 /// </summary> public interface ISingletonDependency : IDependency { } /// <summary> /// 实现该接口将自动注册到Ioc容器,生命周期为每次创建一个新实例 /// </summary> public interface ITransientDependency : IDependency { }
第二步:创建需要注入的功能接口,这类接口就是你想实现某些功能的封装,它们都继承第一步创建的标记接口,如下,我创建一个功能接口
public interface IUserService: IScopeDependency { }
第三步:实现需要注入的功能接口,如下,我创建了一个实现UserService的类
public class UserService: IUserService { }
第四步:扩展IServiceCollection批量注入方法AddDataService
/// <summary> /// 要扫描的程序集名称 /// 默认为[^Shop.Utils|^Shop.]多个使用|分隔 /// </summary> public static string MatchAssemblies = "^Shop.Utils|^Shop."; public static IServiceCollection AddDataService(this IServiceCollection services) { #region 依赖注入 //services.AddScoped<IUserService, UserService>(); var baseType = typeof(IDependency); var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory; var getFiles = Directory.GetFiles(path, "*.dll").Where(Match); //.Where(o=>o.Match()) var referencedAssemblies = getFiles.Select(Assembly.LoadFrom).ToList(); //.Select(o=> Assembly.LoadFrom(o)) var ss = referencedAssemblies.SelectMany(o => o.GetTypes()); var types = referencedAssemblies .SelectMany(a => a.DefinedTypes) .Select(type => type.AsType()) .Where(x => x != baseType && baseType.IsAssignableFrom(x)).ToList(); var implementTypes = types.Where(x => x.IsClass).ToList(); var interfaceTypes = types.Where(x => x.IsInterface).ToList(); foreach (var implementType in implementTypes) { if (typeof(IScopeDependency).IsAssignableFrom(implementType)) { var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType)); if (interfaceType != null) services.AddScoped(interfaceType, implementType); } else if(typeof(ISingletonDependency).IsAssignableFrom(implementType)) { var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType)); if (interfaceType != null) services.AddSingleton(interfaceType, implementType); } else { var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType)); if (interfaceType != null) services.AddTransient(interfaceType, implementType); } } #endregion return services; } /// <summary> /// 程序集是否匹配 /// </summary> public static bool Match(string assemblyName) { assemblyName = Path.GetFileName(assemblyName); if (assemblyName.StartsWith($"{AppDomain.CurrentDomain.FriendlyName}.Views")) return false; if (assemblyName.StartsWith($"{AppDomain.CurrentDomain.FriendlyName}.PrecompiledViews")) return false; return Regex.IsMatch(assemblyName, MatchAssemblies, RegexOptions.IgnoreCase | RegexOptions.Compiled); }
第四步:在Startup.cs调用AddDataService方法进行批量注入
public void ConfigureServices(IServiceCollection services) { services.AddDataService(); }
测试就自己搞定啦:可以在控制器里注入,也可以使用
public static TService GetService<TService>() where TService : class { return HttpContextAccessor.Current.RequestServices.GetService(typeof(TService)) as TService; }
文章评论
- 消灭零回复