ASP.NET Core 反射动态发现类库服务

发布于:2025-04-11 ⋅ 阅读:(50) ⋅ 点赞:(0)


前言

ASP.NET Core中,依赖注入(Dependency Injection, DI)是一种核心设计模式,用于管理对象的创建和生命周期,从而实现松耦合和可测试性
反射动态发现类库服务,适用于需要高度模块化的 ASP.NET Core 应用。

一、反射动态发现类库服务

1)定义公共接口(核心契约)

  1. 创建一个公共类库(例如 SharedContracts),定义服务注册的统一接口。所有其他类库需引用该库

  2. 引用包
    Install-Package Microsoft.Extensions.DependencyInjection
    Install-Package Microsoft.Extensions.Configuration

    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Configuration;
    namespace SharedContracts
    {
        public interface IServiceRegistrar
        {
            //void RegisterServices(IServiceCollection services);
            void RegisterServices(IServiceCollection services, IConfiguration configuration);
        }
    }
    

2)类库实现服务注册逻辑

  1. 每个类库需实现 IServiceRegistrar 接口,封装自身的服务注册代码。

  2. 示例数据访问层类库(DataAccess)
    引用包
    Install-Package Microsoft.Extensions.Configuration
    Install-Package Microsoft.Extensions.DependencyInjection
    Install-Package Microsoft.Extensions.DependencyInjection.Abstractions
    Install-Package Microsoft.EntityFrameworkCore.SqlServer

    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using SharedContracts;
    using Microsoft.EntityFrameworkCore;
    
    namespace DataAccess
    {
        public class DataAccessServiceRegistrar : IServiceRegistrar
        {
            public void RegisterServices(IServiceCollection services, IConfiguration configuration)
            {
                // 注册 DbContext
                services.AddDbContext<AppDbContext>(options =>
                    options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
    
                // 注册其他服务
                //services.AddScoped<IUserRepository, UserRepository>();
            }
        }
    }
    
  3. 示例业务逻辑层类库(BusinessLogic)
    引用包
    Install-Package Microsoft.Extensions.DependencyInjection
    Install-Package Microsoft.Extensions.Configuration

    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using SharedContracts;
    
    namespace BusinessLogic
    {
        public class BusinessLogicServiceRegistrar : IServiceRegistrar
        {
            public void RegisterServices(IServiceCollection services, IConfiguration configuration)
            {
                // 注册业务服务
                services.AddScoped<IUserService, UserServiceImpl>();
                services.AddScoped<IOrderService, OrderServiceImpl>();
            }
        }
    }
    

3)主程序动态加载注册逻辑

  1. ASP.NET Core 主项目的 Program.cs 中,使用反射扫描所有程序集,自动发现并执行注册。

    using System.Reflection;
    using SharedContracts;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // 动态加载所有类库的注册逻辑
    LoadServiceRegistrars(builder.Services, builder.Configuration);
    
    var app = builder.Build();
    app.Run();
    
    // 反射扫描方法
    static void LoadServiceRegistrars(IServiceCollection services, IConfiguration configuration)
    {
        // 获取所有已加载的程序集(可根据项目前缀过滤)
        var assemblies = AppDomain.CurrentDomain.GetAssemblies()
            .Where(a => a.FullName!.StartsWith("YourProjectPrefix")); 
    
        foreach (var assembly in assemblies)
        {
            // 查找所有实现 IServiceRegistrar 的非抽象类
            var registrarTypes = assembly.GetTypes()
                .Where(t => 
                    typeof(IServiceRegistrar).IsAssignableFrom(t) && 
                    !t.IsAbstract && 
                    !t.IsInterface);
    
            foreach (var type in registrarTypes)
            {
                // 创建实例并调用注册方法
                if (Activator.CreateInstance(type) is IServiceRegistrar registrar)
                {
                    registrar.RegisterServices(services, configuration);
                }
            }
        }
    }
    

4)解决程序集未加载问题

  1. 若类库未被主程序直接引用,需确保程序集被加载到当前域。可在主程序中添加以下代码强制加载。

    // 手动加载特定类库程序集(可选)
    var dataAccessAssembly = Assembly.Load("DataAccess");
    var businessLogicAssembly = Assembly.Load("BusinessLogic");
    

二、注意事项

1)性能优化

  1. 限制扫描的程序集范围(如通过 StartsWith(“YourProjectPrefix”)),避免扫描系统程序集。
  2. 缓存扫描结果(如使用静态变量),避免每次启动重复扫描。

2)依赖传递

  1. 确保类库引用了 SharedContracts
  2. 确保必要的 NuGet 包(如 Microsoft.Extensions.DependencyInjection等)。

3)配置隔离

  1. 每个类库的 IServiceRegistrar 实现应仅注册自身服务,避免操作其他类库的配置

4)异常处理

  1. 添加 try-catch 块处理反射过程中的潜在错误(如类型加载失败)。

适用场景

  1. 大型分布式系统,服务按模块拆分到不同类库。
  2. 插件化架构,允许动态加载/卸载功能模块。
  3. 需要严格解耦主程序和类库的项目。

网站公告

今日签到

点亮在社区的每一天
去签到