批量注册DbContext
1 2 3 4 5
| services.AddAllDbContexts(ctx => { string connStr = configuration.GetValue<string>("DefaultDB:ConnStr"); ctx.UseSqlServer(connStr); }, assemblies);
|
AddAllDbContexts是自定义扩展方法,作用是自动注册所有DbContext 类型到依赖注入容器中。
configuration.GetValue<string>(“DefaultDB:ConnStr”)从配置系统中读取连接字符串,我是配置到环境变量。
assemblies 中所有实现了 DbContext 的类,并使用提供的委托配置它们。
AddAllDbContexts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public static class EFCoreInitializerHelper { public static IServiceCollection AddAllDbContexts(this IServiceCollection services, Action<DbContextOptionsBuilder> builder, IEnumerable<Assembly> assemblies) { Type[] types = new Type[] { typeof(IServiceCollection), typeof(Action<DbContextOptionsBuilder>), typeof(ServiceLifetime), typeof(ServiceLifetime) }; var methodAddDbContext = typeof(EntityFrameworkServiceCollectionExtensions) .GetMethod(nameof(EntityFrameworkServiceCollectionExtensions.AddDbContext), 1, types); foreach (var asmToLoad in assemblies) { Type[] typesInAsm = asmToLoad.GetTypes(); foreach (var dbCtxType in typesInAsm .Where(t => !t.IsAbstract && typeof(DbContext).IsAssignableFrom(t))) { var methodGenericAddDbContext = methodAddDbContext.MakeGenericMethod(dbCtxType); methodAddDbContext.Invoke(null, new object[] { services, builder, ServiceLifetime.Scoped, ServiceLifetime.Singleton }); } } return services; } }
|
你这段代码实现了一个 批量注册所有 DbContext 的工具方法 AddAllDbContexts,用于自动扫描并注册多个程序集中的所有 DbContext 类型,避免了手动一个一个写 services.AddDbContext<MyContext>()。
解析
反射查找 AddDbContext<TContext>() 方法
1 2 3
| Type[] types = new Type[] { typeof(IServiceCollection), typeof(Action<DbContextOptionsBuilder>), typeof(ServiceLifetime), typeof(ServiceLifetime) }; var methodAddDbContext = typeof(EntityFrameworkServiceCollectionExtensions) .GetMethod(nameof(EntityFrameworkServiceCollectionExtensions.AddDbContext), 1, types);
|
目标是找到 EF Core 中的泛型方法 AddDbContext<TContext>(this IServiceCollection, Action<DbContextOptionsBuilder>, ServiceLifetime, ServiceLifetime)
GetMethod 的参数 1 表示这个方法有 1 个泛型类型参数。
方法签名中参数为:
1 2 3 4 5 6
| AddDbContext<TContext>( this IServiceCollection services, Action<DbContextOptionsBuilder> optionsAction, ServiceLifetime contextLifetime, ServiceLifetime optionsLifetime )
|
扫描所有程序集中的类型并筛选 DbContext
1 2 3 4 5
| foreach (var asmToLoad in assemblies) { Type[] typesInAsm = asmToLoad.GetTypes(); foreach (var dbCtxType in typesInAsm .Where(t => !t.IsAbstract && typeof(DbContext).IsAssignableFrom(t)))
|
找出当前程序集中所有继承自 DbContext 且不是抽象类的类型。
调用泛型方法 AddDbContext<TContext>
1 2 3 4 5 6 7 8
| var methodGenericAddDbContext = methodAddDbContext.MakeGenericMethod(dbCtxType); methodGenericAddDbContext.Invoke(null, new object[] { services, builder, ServiceLifetime.Scoped, ServiceLifetime.Singleton });
|
先构造泛型方法:比如 AddDbContext<MyDbContext>()
然后反射调用它,传入四个参数。
services 依赖注入容器
builder 用户传入的 ctx => ctx.UseSqlServer(…) 委托
Scoped DbContext 实例的生命周期(推荐使用 Scoped)
Singleton 配置选项的生命周期(通常 Singleton 就可以)