C# MVC中创建身份验证种子用户时出现UserManager服务未注册错误的解决求助
C# MVC中创建身份验证种子用户时出现UserManager服务未注册错误的解决求助
大家好,我刚接触C# MVC,最近在给项目创建身份验证种子用户(一个默认的管理员账号)的时候遇到了问题,想请各位帮忙看看!
我的需求很简单:给数据库初始化一个标准的管理员用户,我写了IdentitySeed类来处理这个逻辑,然后在Program.cs里调用,但运行的时候总是出问题。下面是我的代码:
IdentitySeed 代码
public static class IdentitySeed { public static async Task CreateDefaultUserAsync(IServiceProvider serviceProvider) { var userManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>(); var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>(); string adminEmail = "admin@ybeer.com"; string adminPassword = "Admin@123"; if (!await roleManager.RoleExistsAsync("Admin")) { await roleManager.CreateAsync(new IdentityRole("Admin")); } var user = await userManager.FindByEmailAsync(adminEmail); if (user == null) { user = new IdentityUser { UserName = adminEmail, Email = adminEmail, EmailConfirmed = true }; var result = await userManager.CreateAsync(user, adminPassword); if (result.Succeeded) { await userManager.AddToRoleAsync(user, "Admin"); Console.WriteLine("Usuário administrador criado com sucesso!"); } else { Console.WriteLine("Erro ao criar usuário administrador:"); foreach (var error in result.Errors) { Console.WriteLine(error.Description); } } } } }
Program.cs 代码
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); builder.Services.AddDbContext<CoreDbContext>(options => { options.UseLazyLoadingProxies(); options.ConfigureWarnings(warnings => warnings.Ignore(RelationalEventId.PendingModelChangesWarning)); options.UseNpgsql(connectionString); }); builder.Services.AddDefaultIdentity<AuthUserModel>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<CoreDbContext>(); builder.Services.AddControllersWithViews(); builder.Services.IncludeServices(); var app = builder.Build(); using (var scope = app.Services.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<CoreDbContext>(); dbContext.Database.Migrate(); // Automatically apply migrations Task.Run(async () => { await IdentitySeed.CreateDefaultUserAsync(scope.ServiceProvider); }).GetAwaiter().GetResult(); } // 省略后续中间件配置 }
自定义用户模型 AuthUserModel
public class AuthUserModel : IdentityUser<int> { }
我已经尝试过把_LoginPartial.cshtml里的注入代码从:
@inject SignInManager<IdentityUser> SignInManager @inject UserManager<IdentityUser> UserManager
改成了:
@inject SignInManager<AuthUserModel> SignInManager @inject UserManager<AuthUserModel> UserManager
但还是不行,我猜问题出在类型不匹配上,但我不太清楚具体该怎么改,希望有经验的朋友能指点一下!
问题分析与解决建议
其实核心问题是身份验证组件的泛型类型不统一:你自定义的AuthUserModel继承了IdentityUser<int>(用int作为主键),但你的IdentitySeed里却在请求UserManager<IdentityUser>(默认是string主键),而Program.cs里注册的是针对AuthUserModel的服务,所以容器里找不到UserManager<IdentityUser>,就会抛出服务未注册的错误。
下面是具体的修复步骤:
- 修改IdentitySeed类,统一泛型类型
把UserManager和RoleManager的泛型改成和你的自定义模型匹配的类型:
public static class IdentitySeed { public static async Task CreateDefaultUserAsync(IServiceProvider serviceProvider) { // 改为AuthUserModel对应的UserManager var userManager = serviceProvider.GetRequiredService<UserManager<AuthUserModel>>(); // 因为用了int主键,RoleManager也要用IdentityRole<int> var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole<int>>>(); string adminEmail = "admin@ybeer.com"; string adminPassword = "Admin@123"; if (!await roleManager.RoleExistsAsync("Admin")) { await roleManager.CreateAsync(new IdentityRole<int>("Admin")); } var user = await userManager.FindByEmailAsync(adminEmail); if (user == null) { // 实例化AuthUserModel而不是IdentityUser user = new AuthUserModel { UserName = adminEmail, Email = adminEmail, EmailConfirmed = true }; var result = await userManager.CreateAsync(user, adminPassword); if (result.Succeeded) { await userManager.AddToRoleAsync(user, "Admin"); Console.WriteLine("Usuário administrador criado com sucesso!"); } else { Console.WriteLine("Erro ao criar usuário administrador:"); foreach (var error in result.Errors) { Console.WriteLine(error.Description); } } } } }
- 修正DbContext的继承关系
确保你的CoreDbContext继承了针对int主键的IdentityDbContext:
public class CoreDbContext : IdentityDbContext<AuthUserModel, IdentityRole<int>, int> { public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options) { } // 你的其他DbSet定义 }
- 完善Program.cs中的身份服务注册
添加针对int角色的注册,并且用异步方式调用迁移和种子方法,避免同步阻塞:
public static async Task Main(string[] args) { var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); builder.Services.AddDbContext<CoreDbContext>(options => { options.UseLazyLoadingProxies(); options.ConfigureWarnings(warnings => warnings.Ignore(RelationalEventId.PendingModelChangesWarning)); options.UseNpgsql(connectionString); }); // 添加AddRoles<IdentityRole<int>>来支持int主键的角色 builder.Services.AddDefaultIdentity<AuthUserModel>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<CoreDbContext>() .AddRoles<IdentityRole<int>>(); builder.Services.AddControllersWithViews(); builder.Services.IncludeServices(); var app = builder.Build(); using (var scope = app.Services.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<CoreDbContext>(); // 用异步的MigrateAsync替代同步Migrate await dbContext.Database.MigrateAsync(); // 直接异步调用种子方法,不用Task.Run包装 await IdentitySeed.CreateDefaultUserAsync(scope.ServiceProvider); } // 后续中间件配置... if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.MapRazorPages(); await app.RunAsync(); }
这样修改后,所有身份验证相关的组件都统一使用int主键的自定义模型,服务注册和依赖注入就能匹配上,种子用户应该就能正常创建了。
备注:内容来源于stack exchange,提问作者gustavo deda
相关产品推荐
相关产品推荐

