文章目录
- 前言
- 一、反射动态发现类库服务
- 1)定义公共接口(核心契约)
- 2)类库实现服务注册逻辑
- 3)主程序动态加载注册逻辑
- 4)解决程序集未加载问题
- 二、注意事项
- 1)性能优化
- 2)依赖传递
- 3)配置隔离
- 4)异常处理
- 适用场景
前言
在ASP.NET Core中,依赖注入(Dependency Injection, DI)是一种核心设计模式,用于管理对象的创建和生命周期,从而实现松耦合和可测试性
反射动态发现类库服务,适用于需要高度模块化的 ASP.NET Core 应用。
一、反射动态发现类库服务
1)定义公共接口(核心契约)
-
创建一个公共类库(例如 SharedContracts),定义服务注册的统一接口。所有其他类库需引用该库
-
引用包:
Install-Package Microsoft.Extensions.DependencyInjection
Install-Package Microsoft.Extensions.Configurationusing Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; namespace SharedContracts {public interface IServiceRegistrar{//void RegisterServices(IServiceCollection services);void RegisterServices(IServiceCollection services, IConfiguration configuration);} }
2)类库实现服务注册逻辑
-
每个类库需实现 IServiceRegistrar 接口,封装自身的服务注册代码。
-
示例:数据访问层类库(DataAccess)
引用包:
Install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.DependencyInjection
Install-Package Microsoft.Extensions.DependencyInjection.Abstractions
Install-Package Microsoft.EntityFrameworkCore.SqlServerusing 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){// 注册 DbContextservices.AddDbContext<AppDbContext>(options =>options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));// 注册其他服务//services.AddScoped<IUserRepository, UserRepository>();}} }
-
示例:业务逻辑层类库(BusinessLogic)
引用包:
Install-Package Microsoft.Extensions.DependencyInjection
Install-Package Microsoft.Extensions.Configurationusing 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)主程序动态加载注册逻辑
-
在 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)解决程序集未加载问题
-
若类库未被主程序直接引用,需确保程序集被加载到当前域。可在主程序中添加以下代码强制加载。
// 手动加载特定类库程序集(可选) var dataAccessAssembly = Assembly.Load("DataAccess"); var businessLogicAssembly = Assembly.Load("BusinessLogic");
二、注意事项
1)性能优化
- 限制扫描的程序集范围(如通过 StartsWith(“YourProjectPrefix”)),避免扫描系统程序集。
- 缓存扫描结果(如使用静态变量),避免每次启动重复扫描。
2)依赖传递
- 确保类库引用了 SharedContracts ;
- 确保必要的 NuGet 包(如 Microsoft.Extensions.DependencyInjection等)。
3)配置隔离
- 每个类库的 IServiceRegistrar 实现应仅注册自身服务,避免操作其他类库的配置
4)异常处理
- 添加 try-catch 块处理反射过程中的潜在错误(如类型加载失败)。
适用场景
- 大型分布式系统,服务按模块拆分到不同类库。
- 插件化架构,允许动态加载/卸载功能模块。
- 需要严格解耦主程序和类库的项目。