.NET 7 Clean Architecture项目身份认证报错及上下文工厂疑问
1. 错误原因
你在注册身份服务时使用了AddIdentityCore<IdentityUser>(),这个方法仅提供轻量化的用户身份验证基础服务,但你后续调用了.AddRoles<IdentityRole>(),这会触发RoleManager的注册。然而AddIdentityCore并不会自动注册角色存储接口IRoleStore<IdentityRole>的实现——虽然你加了.AddEntityFrameworkStores<DataBaseContext>(),但这个扩展在AddIdentityCore的调用链中,只会注册用户对应的IUserStore<IdentityUser>,不会自动覆盖角色存储的注册。
DI容器找不到IRoleStore<IdentityRole>的实现,自然无法构造依赖它的RoleManager,以及依赖RoleManager的UserClaimsPrincipalFactory,最终抛出你看到的错误。
另外你的DbContext注册还有个小问题:option.UseSqlServer()没有传入连接字符串,这会导致后续数据库连接失败,需要补上从配置中读取的连接字符串。
2. ContextFactory是不是正确的解决方式?
完全不是。IDesignTimeDbContextFactory是给EF Core的设计时工具用的(比如执行Add-Migration、Update-Database这类迁移命令),和你当前遇到的运行时DI服务注入问题无关,它解决不了角色服务缺失的问题。
修复方案
方案一:改用完整的AddIdentity(推荐,适合需要完整用户+角色功能的场景)
把AddIdentityCore替换为AddIdentity,它会自动注册用户和角色的所有必要服务,包括对应的存储实现:
services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<DataBaseContext>() .AddDefaultTokenProviders();
同时修复DbContext的连接字符串配置:
services.AddDbContext<DataBaseContext>(option => { option.UseSqlServer(configuration.GetConnectionString("ConnectionStringName")); });
方案二:保留AddIdentityCore,手动补充角色存储(适合轻量化场景)
如果确实需要使用AddIdentityCore的轻量化特性,需要手动注册角色存储的EF Core实现:
services.AddIdentityCore<IdentityUser>() .AddRoles<IdentityRole>() .AddEntityFrameworkStores<DataBaseContext>() .AddDefaultTokenProviders(); // 手动注册角色存储实现 services.AddScoped<IRoleStore<IdentityRole>, RoleStore<IdentityRole, DataBaseContext>>();
同样要记得给UseSqlServer传入正确的连接字符串。
额外说明
你的ContextFactory可以保留,它在执行EF Core迁移命令时会正常工作,但对当前的运行时错误没有帮助。
内容的提问来源于stack exchange,提问作者movahedijam

