ASP.NET Core WebAPI依赖注入封装

本文介绍了如何在WebAPI项目中利用AsmResolver库进行依赖注入封装,通过自定义接口和实现类,以及AssemblyHelper类来自动扫描并初始化所有引用的模块中的服务。同时展示了在.NETCore3.1和.NET6中的使用方法。
摘要由CSDN通过智能技术生成

WebAPI依赖注入封装

1、安装依赖包

#AsmResolver.DotNet
NuGet\Install-Package AsmResolver.DotNet -Version 5.1.0
dotnet add package AsmResolver.DotNet --version 5.1.0

#AsmResolver
dotnet add package AsmResolver --version 5.1.0
NuGet\Install-Package AsmResolver -Version 5.1.0

2、新建接口及实现类

接口

//引用的命名空间
using Microsoft.Extensions.DependencyInjection;

/// <summary>
    /// 所有项目中的实现了IModuleInitializer接口都会被调用,请在Initialize中编写注册本模块需要的服务。
    /// 一个项目中可以放多个实现了IModuleInitializer的类。不过为了集中管理,还是建议一个项目中只放一个实现了IModuleInitializer的类
    /// </summary>
    public interface IModuleInitializer
    {
        public void Initialize(IServiceCollection services);
    }

实现类

//引用的命名空间
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

public static class ModuleInitializer
    {
        /// <summary>
        /// 每个项目中都可以自己写一些实现了IModuleInitializer接口的类,在其中注册自己需要的服务,这样避免所有内容到入口项目中注册
        /// </summary>
        /// <param name="services"></param>
        /// <param name="assemblies"></param>
        public static IServiceCollection RunModuleInitializers(this IServiceCollection services,
         IEnumerable<Assembly> assemblies)
        {
            foreach (var asm in assemblies)
            {
                Type[] types = asm.GetTypes();
                var moduleInitializerTypes = types.Where(t => !t.IsAbstract && typeof(IModuleInitializer).IsAssignableFrom(t));
                foreach (var implType in moduleInitializerTypes)
                {
                    var initializer = (IModuleInitializer?)Activator.CreateInstance(implType);
                    if (initializer == null)
                    {
                        throw new ApplicationException($"Cannot create ${implType}");
                    }
                    initializer.Initialize(services);
                }
            }
            return services;
        }
    }

程序集帮助类

//应用命名空间
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;

    public static class AssemblyHelper
    {
        /// <summary>
        /// 据产品名称获取程序集
        /// </summary>
        /// <param name="productName"></param>
        /// <returns></returns>
        public static IEnumerable<Assembly> GetAssembliesByProductName(string productName)
        {
            var asms = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var asm in asms)
            {
                var asmCompanyAttr = asm.GetCustomAttribute<AssemblyProductAttribute>();
                if (asmCompanyAttr != null && asmCompanyAttr.Product == productName)
                {
                    yield return asm;
                }
            }
        }
        //是否是微软等的官方Assembly
        private static bool IsSystemAssembly(Assembly asm)
        {
            var asmCompanyAttr = asm.GetCustomAttribute<AssemblyCompanyAttribute>();
            if (asmCompanyAttr == null)
            {
                return false;
            }
            else
            {
                string companyName = asmCompanyAttr.Company;
                return companyName.Contains("Microsoft");
            }
        }

        private static bool IsSystemAssembly(string asmPath)
        {
            var moduleDef = AsmResolver.DotNet.ModuleDefinition.FromFile(asmPath);
            var assembly = moduleDef.Assembly;
            if (assembly == null)
            {
                return false;
            }
            var asmCompanyAttr = assembly.CustomAttributes.FirstOrDefault(c => c.Constructor?.DeclaringType?.FullName == typeof(AssemblyCompanyAttribute).FullName);
            if (asmCompanyAttr == null)
            {
                return false;
            }
            var companyName = ((AsmResolver.Utf8String?)asmCompanyAttr.Signature?.FixedArguments[0]?.Element)?.Value;
            if (companyName == null)
            {
                return false;
            }
            return companyName.Contains("Microsoft");
        }

        /// <summary>
        /// 判断file这个文件是否是程序集
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        private static bool IsManagedAssembly(string file)
        {
            using var fs = File.OpenRead(file);
            using PEReader peReader = new PEReader(fs);
            return peReader.HasMetadata && peReader.GetMetadataReader().IsAssembly;
        }

        private static Assembly? TryLoadAssembly(string asmPath)
        {
            AssemblyName asmName = AssemblyName.GetAssemblyName(asmPath);
            Assembly? asm = null;
            try
            {
                asm = Assembly.Load(asmName);
            }
            catch (BadImageFormatException ex)
            {
                Debug.WriteLine(ex);
            }
            catch (FileLoadException ex)
            {
                Debug.WriteLine(ex);
            }

            if (asm == null)
            {
                try
                {
                    asm = Assembly.LoadFile(asmPath);
                }
                catch (BadImageFormatException ex)
                {
                    Debug.WriteLine(ex);
                }
                catch (FileLoadException ex)
                {
                    Debug.WriteLine(ex);
                }
            }
            return asm;
        }

        /// <summary>
        /// loop through all assemblies
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Assembly> GetAllReferencedAssemblies(bool skipSystemAssemblies = true)
        {
            Assembly? rootAssembly = Assembly.GetEntryAssembly();
            if (rootAssembly == null)
            {
                rootAssembly = Assembly.GetCallingAssembly();
            }
            var returnAssemblies = new HashSet<Assembly>(new AssemblyEquality());
            var loadedAssemblies = new HashSet<string>();
            var assembliesToCheck = new Queue<Assembly>();
            assembliesToCheck.Enqueue(rootAssembly);
            if (skipSystemAssemblies && IsSystemAssembly(rootAssembly) != false)
            {
                if (IsValid(rootAssembly))
                {
                    returnAssemblies.Add(rootAssembly);
                }
            }
            while (assembliesToCheck.Any())
            {
                var assemblyToCheck = assembliesToCheck.Dequeue();
                foreach (var reference in assemblyToCheck.GetReferencedAssemblies())
                {
                    if (!loadedAssemblies.Contains(reference.FullName))
                    {
                        var assembly = Assembly.Load(reference);
                        if (skipSystemAssemblies && IsSystemAssembly(assembly))
                        {
                            continue;
                        }
                        assembliesToCheck.Enqueue(assembly);
                        loadedAssemblies.Add(reference.FullName);
                        if (IsValid(assembly))
                        {
                            returnAssemblies.Add(assembly);
                        }
                    }
                }
            }
            var asmsInBaseDir = Directory.EnumerateFiles(AppContext.BaseDirectory,
                "*.dll", new EnumerationOptions { RecurseSubdirectories = true });
            foreach (var asmPath in asmsInBaseDir)
            {
                if (!IsManagedAssembly(asmPath))
                {
                    continue;
                }
                AssemblyName asmName = AssemblyName.GetAssemblyName(asmPath);
                //如果程序集已经加载过了就不再加载
                if (returnAssemblies.Any(x => AssemblyName.ReferenceMatchesDefinition(x.GetName(), asmName)))
                {
                    continue;
                }
                if (skipSystemAssemblies && IsSystemAssembly(asmPath))
                {
                    continue;
                }
                Assembly? asm = TryLoadAssembly(asmPath);
                if (asm == null)
                {
                    continue;
                }
                //Assembly asm = Assembly.Load(asmName);
                if (!IsValid(asm))
                {
                    continue;
                }
                if (skipSystemAssemblies && IsSystemAssembly(asm))
                {
                    continue;
                }
                returnAssemblies.Add(asm);
            }
            return returnAssemblies.ToArray();
        }

        private static bool IsValid(Assembly asm)
        {
            try
            {
                asm.GetTypes();
                asm.DefinedTypes.ToList();
                return true;
            }
            catch (ReflectionTypeLoadException)
            {
                return false;
            }
        }

        class AssemblyEquality : EqualityComparer<Assembly>
        {
            public override bool Equals(Assembly? x, Assembly? y)
            {
                if (x == null && y == null) return true;
                if (x == null || y == null) return false;
                return AssemblyName.ReferenceMatchesDefinition(x.GetName(), y.GetName());
            }

            public override int GetHashCode([DisallowNull] Assembly obj)
            {
                return obj.GetName().FullName.GetHashCode();
            }
        }
    }

实现方法

//引用的命名空间
using Microsoft.Extensions.DependencyInjection;

public class ModuleInit : IModuleInitializer
{
    public void Initialize(IServiceCollection services)
    {
    	//要注入的接口
        services.AddScoped<IPersonsServices, PersonsServices>();
    }
}

4、在StartUp(.Net Core 3.1)或者Program(.Net 6及以上)中使用

//之前的注入方式
//Services.AddScoped<IPersonsServices, PersonsServices>();
//builder.Services.AddScoped<IPersonsServices, PersonsServices>();
//现在的注入方式
//.net core 3.1中
Services.RunModuleInitializers(AssemblyHelper.GetAllReferencedAssemblies());
//.Net6中
builder.Services.RunModuleInitializers(AssemblyHelper.GetAllReferencedAssemblies());
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值