You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>,就会抛出服务未注册的错误。

下面是具体的修复步骤:

  1. 修改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);
                }
            }
        }
    }
}
  1. 修正DbContext的继承关系
    确保你的CoreDbContext继承了针对int主键的IdentityDbContext:
public class CoreDbContext : IdentityDbContext<AuthUserModel, IdentityRole<int>, int>
{
    public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options)
    {
    }

    // 你的其他DbSet定义
}
  1. 完善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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 12:14:33