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

在ASP.NET Core MVC(.NET6)的Program.cs中无法创建用户并分配角色

问题:ASP.NET Core MVC (.NET 6) 初始化角色与用户失败,外键约束冲突

问题描述

项目基于ASP.NET Core MVC + .NET 6,尝试初始化一个不存在的角色并创建拥有该角色的用户,但多次调整代码仍未成功。首次运行应用时,在执行将用户添加到角色的代码行时触发错误,数据库中角色已成功创建,但用户未生成。

错误信息

Microsoft.EntityFrameworkCore.DbUpdateException: 'An error occurred while saving the entity changes. See the inner exception for details.'
SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_AspNetUserRoles_AspNetUsers_UserId". The conflict occurred in database "ViewMovies", table "dbo.AspNetUsers", column 'Id'.
The statement has been terminated.

现有代码

Program.cs 初始化逻辑

var app = builder.Build();
var scope = app.Services
                .GetService<IServiceScopeFactory>()
                ?.CreateScope();

if (scope is not null)
{
    using (scope)
    {
        var roleManager = scope
            .ServiceProvider
            .GetService<RoleManager<IdentityRole>>();
        var userManager = scope
            .ServiceProvider
            .GetRequiredService<UserManager<User>>();
        
        Task
        .Run(async () =>
        {
            if (await roleManager.RoleExistsAsync("test"))
            {
                return;
            }

            var role = new IdentityRole { Name = "test" };
            await roleManager.CreateAsync(role);

            const string testEmail = "test@role.com";
            const string testPassword = "test123";
            var user = new User
            {
                Email = testEmail,
                UserName = testEmail
            };

            await userManager.CreateAsync(user, testPassword);
            await userManager.AddToRoleAsync(user, role.Name);
        })
        .GetAwaiter()
        .GetResult();
    }
}

服务注册代码

builder.Services.AddDefaultIdentity<User>()
                .AddRoles<IdentityRole>()
                .AddRoleManager<RoleManager<IdentityRole>>()
                .AddEntityFrameworkStores<ViewMoviesDbContext>();

问题根源

  1. 同步阻塞异步代码:使用Task.Run().GetAwaiter().GetResult()强制同步等待异步操作,会导致Entity Framework Core上下文状态异常——userManager.CreateAsync可能还未完成用户的数据库持久化(用户Id未生成),就执行了AddToRoleAsync,触发外键约束冲突。
  2. 未校验操作结果:没有验证CreateAsync的返回结果,若用户创建失败(比如密码不符合规则),后续角色分配必然报错。
  3. RoleManager可能为null:使用GetService<RoleManager<IdentityRole>>()获取服务,若依赖注入未正确注册,会返回null导致后续逻辑异常。

解决方案

修改初始化逻辑为纯异步执行,并添加操作结果校验:

var app = builder.Build();

// 初始化角色与用户
using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;
    var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
    var userManager = services.GetRequiredService<UserManager<User>>();

    await InitializeRolesAndUsersAsync(roleManager, userManager);
}

// 后续中间件配置(示例)
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

async Task InitializeRolesAndUsersAsync(RoleManager<IdentityRole> roleManager, UserManager<User> userManager)
{
    const string roleName = "test";
    const string testEmail = "test@role.com";
    const string testPassword = "test123";

    // 检查角色是否已存在
    if (await roleManager.RoleExistsAsync(roleName))
    {
        return;
    }

    // 创建角色并校验结果
    var roleCreateResult = await roleManager.CreateAsync(new IdentityRole(roleName));
    if (!roleCreateResult.Succeeded)
    {
        foreach (var error in roleCreateResult.Errors)
        {
            Console.WriteLine($"角色创建失败: {error.Description}");
        }
        return;
    }

    // 检查用户是否已存在
    var existingUser = await userManager.FindByEmailAsync(testEmail);
    if (existingUser != null)
    {
        return;
    }

    // 创建用户并校验结果
    var user = new User
    {
        Email = testEmail,
        UserName = testEmail
    };
    var userCreateResult = await userManager.CreateAsync(user, testPassword);
    if (!userCreateResult.Succeeded)
    {
        foreach (var error in userCreateResult.Errors)
        {
            Console.WriteLine($"用户创建失败: {error.Description}");
        }
        return;
    }

    // 分配角色并校验结果
    var roleAssignResult = await userManager.AddToRoleAsync(user, roleName);
    if (!roleAssignResult.Succeeded)
    {
        foreach (var error in roleAssignResult.Errors)
        {
            Console.WriteLine($"角色分配失败: {error.Description}");
        }
    }
}

关键修改点

  • 移除同步阻塞逻辑,用await确保异步操作按顺序执行,保证用户Id生成后再分配角色
  • 使用GetRequiredService替代GetService,避免RoleManager为null
  • 添加角色、用户的存在性检查,避免重复创建
  • 校验所有Identity操作的返回结果,快速定位失败原因

内容的提问来源于stack exchange,提问作者FadoBagi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:35:17