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

文章目录


前言

ASP.NET Core 中,依赖注入(Dependency Injection, DI )是一种核心设计模式,用于管理对象的创建和生命周期,从而实现松耦合和可测试性

反射动态发现类库服务,适用于需要高度模块化的 ASP.NET Core 应用。

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

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

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

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

    csharp 复制代码
    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

    csharp 复制代码
    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

    csharp 复制代码
    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 中,使用反射扫描所有程序集,自动发现并执行注册。

    csharp 复制代码
    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. 若类库未被主程序直接引用,需确保程序集被加载到当前域。可在主程序中添加以下代码强制加载。

    csharp 复制代码
    // 手动加载特定类库程序集(可选)
    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. 需要严格解耦主程序和类库的项目。
相关推荐
用户685453759776914 分钟前
同步成本换并行度:多线程、协程、分片、MapReduce 怎么选才不踩坑
后端
javaTodo21 分钟前
Claude Code 记忆机制详解:从 CLAUDE.md 到 Auto Memory,六层体系全拆解
后端
LSTM9742 分钟前
使用 C# 和 Spire.PDF 从 HTML 模板生成 PDF 的实用指南
后端
JaguarJack1 小时前
为什么 PHP 闭包要加 static?
后端·php·服务端
BingoGo1 小时前
为什么 PHP 闭包要加 static?
后端
是糖糖啊1 小时前
OpenClaw 从零到一实战指南(飞书接入)
前端·人工智能·后端
百度Geek说1 小时前
基于Spark的配置化离线反作弊系统
后端
Java编程爱好者2 小时前
虚拟线程深度解析:轻量并发编程的未来趋势
后端
苏三说技术2 小时前
Spring AI 和 LangChain4j ,哪个更好?
后端