ASP.NET Core中NormalizedEmail未写入AspNetUsers表问题求助
问题描述
我在多个项目中使用Asp.Net Identity管理器均运行正常,对比其他代码库,除了Startup类中的密码规则覆盖外,逻辑完全一致,但无法理解为何NormalizedEmail字段未被添加到AspNetUsers表中。
相关代码
Startup.cs 配置代码
.AddEntityFrameworkStores<CorporateIdentityContext>() .AddDefaultTokenProviders(); //override identity Password rule services.Configure<IdentityOptions>(opts => { opts.Password.RequiredLength = 6; opts.Password.RequireNonAlphanumeric = false; opts.Password.RequireLowercase = false; //opts.Password.RequireUppercase = true; opts.Password.RequireDigit = false; opts.User.RequireUniqueEmail = true; //opts.SignIn.RequireConfirmedEmail = false; opts.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+"; //options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+/"; //opts.User.AllowedUserNameCharacters = null; });
用户创建方法代码
public async Task<ServiceResponse<GetUserDto>> RegisterUser(UserDto payload) { var serviceResponse = new ServiceResponse<GetUserDto>(); //检查用户是否存在 var CorporateUser = await _userManager.FindByNameAsync(payload.Email); if (CorporateUser != null) { _logger.LogInformation($"User already exist for this email: {CorporateUser.Email}"); serviceResponse.Message = $"User already exist for this email: {CorporateUser.Email}"; serviceResponse.Success = false; return serviceResponse; } var password = Helper.ServiceHelper.GeneratePassword(7); var uniqueId = ServiceHelper.GeneratePolNumber(); var refnum = ServiceHelper.GeneratePropNumber(); var newUser = new CorporateIdentityUser { Email = payload.Email, UserName = payload.UserName, UserUniqueId = uniqueId, NormalizedEmail = payload.Email.ToUpper(), //NormalizedUserName = payload.Email, RefrenceId = refnum, FirstName = payload.FirstName, LastName = payload.LastName, CompanyName = payload.CompanyName, BrokerName = payload.BrokerName, AccountType = "Generaluser", Country = payload.Country, RcNumber = payload.RcNumber, DateCreated = DateTime.Now, Address = payload.Address, Occupation = payload.Occupation, Gender =payload.Gender, DateofBirth = payload.DateofBirth, IsActive = false, IsWallet = false, IsBroker = false, PhoneNumber = payload.PhoneNumber, SecurityStamp = Guid.NewGuid().ToString() }; try { var result = await _userManager.CreateAsync(newUser, password); if (!result.Succeeded) { var errorMsg = string.Empty; foreach (var error in result.Errors) { _logger.LogError($"The error occur while registring {newUser.Email}: {error.Code}, {error.Description}"); errorMsg = error.Description; } serviceResponse.Message = errorMsg; serviceResponse.Success = false; } else { var confirmEmailToken = await _userManager.GenerateEmailConfirmationTokenAsync(newUser); var encodedEmailToken = Encoding.UTF8.GetBytes(confirmEmailToken); var validEmailtoken = WebEncoders.Base64UrlEncode(encodedEmailToken); var body = new Dictionary<string, object>() { { "name", payload.FirstName.ToUpper() +" "+ payload.LastName}, { "password", password}, {"email", payload.Email }, {"temp_id", 27059391} }; await Helper.ServiceHelper.SendEmailVerificationViaPostmarkAsync(body); serviceResponse.Data = _mapper.Map<GetUserDto>(newUser); serviceResponse.Message = "Registration Successful"; serviceResponse.Success = true; _logger.LogInformation($"Registration successfull for this username: {newUser.Email}"); } } catch (Exception ex) { string error = ex.Message; serviceResponse.Message= error; _logger.LogError($"Error occured! Message {ex.Message} Stack Trace {ex.StackTrace}"); } return serviceResponse; }
排查方向与解决方案
1. 移除手动赋值,依赖UserManager自动处理
Asp.Net Identity的UserManager.CreateAsync方法内部会自动规范化NormalizedEmail和NormalizedUserName,遵循IdentityOptions中的配置。手动赋值的NormalizedEmail可能被该方法的内部逻辑覆盖,导致最终写入数据库的值异常(或为空)。
解决方案:删除newUser初始化时的NormalizedEmail = payload.Email.ToUpper()代码,让UserManager自动完成规范化操作。
2. 检查实体类定义
确保CorporateIdentityUser正确继承自IdentityUser,这样才能继承NormalizedEmail等核心属性,且EF Core能正确映射到数据库表:
public class CorporateIdentityUser : IdentityUser { // 自定义属性 public string UserUniqueId { get; set; } public string RefrenceId { get; set; } // ...其他自定义属性 }
如果是完全自定义的属性,需确保NormalizedEmail为public属性,且通过数据注解(如[Column("NormalizedEmail")])或Fluent API正确映射到数据库字段。
3. 验证数据库表结构
确认AspNetUsers表中存在NormalizedEmail列,若不存在,需生成EF Core迁移并更新数据库:
# 生成迁移 Add-Migration AddNormalizedEmailColumn # 更新数据库 Update-Database
4. 调试验证
在调用CreateAsync前后分别打印newUser.NormalizedEmail的值,观察是否被修改;同时启用EF Core日志,查看插入语句中是否包含NormalizedEmail字段,确认数据库操作的细节。
内容的提问来源于stack exchange,提问作者techstack

