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

ASP.NET Identity:NormalizedEmail与NormalizedUserName被强制转小写问题

问题描述

在单元测试中同步调用异步方法时遇到异常现象:

  1. 手动创建IdentityUser实例并设置NormalizedEmail、NormalizedUserName为大写,调用_userManager.CreateAsync后,这两个属性及数据库对应值变为小写。
  2. 从数据库重新查询用户并手动重置这两个属性为大写,调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 11:44:57