ASP.NET Identity:NormalizedEmail与NormalizedUserName被强制转小写问题
问题描述
在单元测试中同步调用异步方法时遇到异常现象:
- 手动创建
IdentityUser实例并设置NormalizedEmail、NormalizedUserName为大写,调用_userManager.CreateAsync后,这两个属性及数据库对应值变为小写。 - 从数据库重新查询用户并手动重置这两个属性为大写,调用
SaveChanges后状态正常,但调用_userManager.AddClaimAsync后,属性又变回小写。
相关代码片段:
初始创建代码
var identityUser = new IdentityUser(email) { Email = email, PhoneNumber = phone }; identityUser.NormalizedEmail = identityUser.Email.Normalize().ToUpperInvariant(); identityUser.NormalizedUserName = identityUser.UserName?.Normalize().ToUpperInvariant(); // activate user identityUser.EmailConfirmed = true; identityUser.PhoneNumberConfirmed = true; identityUser.LockoutEnabled = false; var result = _store.SetUserNameAsync(identityUser, identityUser.Email, CancellationToken.None); result.Wait(); if (!result.IsCompletedSuccessfully) throw new Exception($"Failed to create username {identityUser.UserName}: {result.Exception?.Message}"); var identityCreateResult = _userManager.CreateAsync(identityUser, password).Result; if (!identityCreateResult.Succeeded) throw new Exception($"Failed to create user {identityUser.UserName}: {identityCreateResult.Errors.First().Description}");
修复代码(首次重置)
identityUser = identityContext.Users.First(x => x.Id == identityUser.Id); identityUser.NormalizedEmail = identityUser.Email.ToUpperInvariant(); identityUser.NormalizedUserName = identityUser.UserName?.ToUpperInvariant(); // activate user identityUser.EmailConfirmed = true; identityUser.PhoneNumberConfirmed = true; identityUser.LockoutEnabled = false; identityContext.SaveChanges();
触发二次异常的代码
var claim = new Claim("Manager", "_states"); _ = _userManager.AddClaimAsync(identityUser, claim).Result;
所有文档均说明Normalized属性是对常规属性执行Normalize().ToUpperInvariant()后的结果,此现象不符合预期,求原因。
问题原因分析
- Identity内部自动覆盖规范化值:
UserManager的核心方法(比如CreateAsync、AddClaimAsync)执行时,会自动触发对Email、UserName的规范化操作,直接覆盖你手动设置的Normalized属性值。 - 规范化规则被篡改:默认情况下Identity会将值转大写,但如果项目中自定义了
UserStore,或者修改了ILookupNormalizer规范化器的实现,可能被改成了转小写逻辑。 - DbContext跟踪导致的状态刷新:调用
UserManager方法时,它会重新从上下文获取或跟踪用户实体,此时Identity内部的规范化逻辑会重新计算Normalized属性,覆盖你之前手动设置的大写值。 - 同步调用异步方法的状态不一致:用
.Result阻塞调用异步方法,可能导致DbContext的实体跟踪状态异常,使得规范化逻辑在错误时机触发。
简单来说,CreateAsync和AddClaimAsync执行时,都会调用UserStore的规范化方法,若你的项目里规范化规则被改成了转小写,或者默认逻辑被意外修改,就会出现手动设置的大写值被覆盖的情况。
内容的提问来源于stack exchange,提问作者David Thielen
相关产品推荐
相关产品推荐

