.NET Core中实现自动注入、批量注入

  • binGe博客
  • NetCore
  • 2022-1-27 14:59:06
  • 人已阅读
简介我们在使用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;
        }

文章评论

评论
  • 消灭零回复
Top