.NET 5应用可成功创建数据库但无法写入种子数据的问题排查
问题核心原因
- 上下文不一致:控制器中手动创建的
DataContext连接的是你指定的新库,而注入的_roleManager默认绑定的是程序初始化时注入的DataContext实例,两者连接的数据库完全不同,写入操作实际作用在了默认配置的数据库而非你刚创建的新库。 - 异步方法调用不规范:
roleManager.CreateAsync是异步方法,直接用Wait()可能引发ASP.NET Core的同步上下文死锁,且未捕获返回的IdentityResult结果,无法排查验证报错(比如角色名格式不符合配置要求等)。 - 读写上下文分离:你用手动创建的
DataContext判断是否存在角色,用另一个上下文的RoleManager写入,两者状态不共享,可能出现判断逻辑和写入逻辑不同步的问题。
解决方法
方案1:直接复用手动创建的上下文写入(最简便,适合种子数据场景)
直接用你刚创建的DataContext插入角色,绕开RoleManager的上下文绑定问题,修改SeedRoles代码:
public static void SeedRoles(DataContext context) { if (!context.Roles.Any()) { var roles = new List<Role> { new Role{Name = "Admin", NormalizedName = "ADMIN"}, new Role{Name = "Standard", NormalizedName = "STANDARD"}, new Role{Name = "Basic", NormalizedName = "BASIC"} }; context.Roles.AddRange(roles); context.SaveChanges(); } }
调用时直接传你手动创建的context即可:Seed.SeedRoles(context);
注意要手动给NormalizedName赋值,Identity相关表需要这个字段用于规范化查询。
方案2:手动构造对应上下文的RoleManager(需要保留RoleManager逻辑时使用)
如果你必须用RoleManager的逻辑(比如要触发自定义的角色验证、事件等),需要基于你新创建的DataContext手动构造RoleManager实例,代码参考:
[HttpGet("NewDb/{dbName}")] public async Task CreateNewDb(string dbName) { var optionsBuilder = new DbContextOptionsBuilder<DataContext>() .UseMySql("server=localhost; user=username; password=password;database=" + dbName, new MySqlServerVersion(new Version(8, 0, 21))); DataContext context = new DataContext(optionsBuilder.Options); context.Database.Migrate(); // 手动构造RoleStore和RoleManager,绑定当前新建的context var roleStore = new RoleStore<Role>(context); var roleManager = new RoleManager<Role>(roleStore, new List<IRoleValidator<Role>>{new RoleValidator<Role>()}, UpperInvariantLookupNormalizer.Instance, new IdentityErrorDescriber(), null); await Seed.SeedRoles(roleManager); }
同时修改SeedRoles为异步方法,处理返回结果:
public static async Task SeedRoles(RoleManager<Role> roleManager) { if (!await roleManager.Roles.AnyAsync()) { var roles = new List<Role> { new Role{Name = "Admin"}, new Role{Name = "Standard"}, new Role{Name = "Basic"} }; foreach (var role in roles) { var result = await roleManager.CreateAsync(role); // 可自行添加日志输出result.Errors排查错误 if(!result.Succeeded) { throw new Exception($"角色{role.Name}创建失败:{string.Join(",", result.Errors.Select(e=>e.Description))}"); } } } }
内容的提问来源于stack exchange,提问作者GolfBravo
相关产品推荐
相关产品推荐

