ASP.NET MVC中Identity脚手架引发ApplicationDbContext冲突问题求助
问题背景
实现基础CRUD操作时定义了ApplicationDbContext并注册到服务容器;同时通过Identity脚手架生成了另一个同名的ApplicationDbContext,脚手架也自动完成了服务注册。现在出现服务容器冲突,CRUD相关的上下文验证失败,错误信息如下:
AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: BulkyBook.DataAccess.Repository.IRepository.IUnitOfWork Lifetime: Scoped ImplementationType: BulkyBook.DataAccess.Repository.UnitOfWork': Unable to resolve service for type 'BulkyBook.DataAccess.ApplicationDbContext' while attempting to activate 'BulkyBook.DataAccess.Repository.UnitOfWork'.)
问题根源
你定义了两个同名的ApplicationDbContext类(即使在不同文件,只要命名空间一致就会造成冲突)。编译器会自动覆盖其中一个类,导致服务容器中实际注册的上下文与UnitOfWork依赖的上下文不匹配,最终出现无法解析服务的错误。
解决方案:合并上下文(推荐)
将业务CRUD和Identity的上下文合并为一个,这是ASP.NET Core中整合业务数据与身份数据的标准做法:
- 删除重复的上下文类:保留脚手架生成的带
IdentityUser泛型的版本(它包含Identity的基础配置),删除CRUD操作对应的同名类。 - 添加业务实体的DbSet:在保留的上下文中加入CRUD所需的实体集合。
- 保留Identity自定义逻辑:如果需要修改Identity表结构或规则,继续使用
OnModelCreating方法。
修改后的ApplicationDbContext代码:
public class ApplicationDbContext : IdentityDbContext<IdentityUser> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } // 业务实体DbSet public DbSet<Category> Categories { get; set; } public DbSet<CoverType> CoverType { get; set; } public DbSet<Product> Products { get; set; } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // 可在这里添加Identity表自定义逻辑(如重命名表名) } }
Program.cs代码无需调整:
原来的服务注册逻辑现在会指向唯一的ApplicationDbContext,不会再出现冲突:
builder.Services.AddControllersWithViews(); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConection"))); builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>(); builder.Services.AddScoped<IUnitOfWork, UnitOfWork>(); builder.Services.AddRazorPages().AddRazorRuntimeCompilation(); var app = builder.Build();
可选方案:分离上下文(不推荐)
如果确实需要将业务数据与Identity数据分离为不同上下文,需:
- 给两个上下文起不同的类名(如
AppDbContext和IdentityDbContext) - 分别注册到服务容器,可指定同一或不同连接字符串
- 修改
UnitOfWork和Identity相关代码,分别依赖对应的上下文
但此方案会增加数据库操作的复杂度,仅在业务与身份数据完全隔离时考虑使用。
内容的提问来源于stack exchange,提问作者Hassan oladipupo

