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

ASP.NET Core更新用户(含/不含密码)模型复用与Json异常问题

问题解决方案

问题1:模型校验规则冲突解决

核心原因是同一个DTO同时适配两个业务场景导致校验规则冲突,有两种可行方案:

  • 方案1(推荐):拆分不同场景的DTO
    拆分出两个独立的模型:CreateUserModel(用于新建用户)和UpdateUserModel(用于更新用户)。CreateUserModel的密码字段加[Required]特性,UpdateUserModel的密码字段不加强制必填校验,只保留长度、一致性校验即可。该方案耦合度最低,后续业务规则变更时维护成本最低。
  • 方案2:实现条件校验
    如果不想拆分模型,可以让RegisterModel实现IValidatableObject接口,在Validate方法中根据场景判断是否需要校验密码必填:
    public class RegisterModel : IValidatableObject
    {
        // 原有属性保持不变
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            // Id为空说明是新建用户场景,密码必填
            if (string.IsNullOrEmpty(Id) && string.IsNullOrEmpty(Password))
            {
                yield return new ValidationResult("密码为必填项", new[] { nameof(Password) });
            }
            // 密码不为空时,校验确认密码是否一致
            if (!string.IsNullOrEmpty(Password) && Password != ConfirmPassword)
            {
                yield return new ValidationResult("两次输入的密码不一致", new[] { nameof(ConfirmPassword) });
            }
        }
    }
    

问题2:JSON反序列化异常解决

异常的直接原因是接口返回格式不统一:你当前NotFound返回的是纯文本字符串,且代码存在逻辑漏洞可能触发服务器返回非JSON格式的错误内容,前端统一将响应体反序列化为RegisterResult类型时解析失败。
修复步骤如下:

  1. 修正用户存在性判断逻辑,原逻辑判断model.Email是否为空完全错误,应该先判断查询出来的existingUser是否为null
  2. 所有接口返回值统一为RegisterResult格式,不要返回纯文本
  3. 移除冗余的导航属性赋值和重复哈希逻辑,避免EF Core跟踪冲突
    修改后的UpdateUser方法参考:
public async Task<IActionResult> UpdateUser([FromBody] RegisterModel model)
{
    ApplicationUser existingUser = await this.UserManager.FindByIdAsync(model.Id);
    // 先判断用户是否存在,统一返回JSON格式
    if (existingUser == null)
    {
        return NotFound(new RegisterResult { Successful = false, Errors = new List<string> { "User not found!" } });
    }

    IList<string> existingRoles = await this.UserManager.GetRolesAsync(existingUser);
    if (existingRoles.Any())
    {
        await this.UserManager.RemoveFromRoleAsync(existingUser, existingRoles.FirstOrDefault());
    }
    await this.UserManager.AddToRoleAsync(existingUser, model.UserRoles);

    // 不要手动给UserRoles导航属性赋值,UserManager已经处理了角色关联
    existingUser.Email = model.Email;
    existingUser.FirstName = model.FirstName;
    existingUser.LastName = model.LastName;
    existingUser.ProfilePicture = model.ProfilePicture;

    if (!string.IsNullOrEmpty(model.Password))
    {
        // 不要重复哈希,模型的Compare特性已经保证两次密码一致,仅需哈希一次即可
        existingUser.PasswordHash = this.PasswordHasher.HashPassword(existingUser, model.Password);
    }

    IdentityResult result = await this.UserManager.UpdateAsync(existingUser);
    if (!result.Succeeded)
    {
        var errors = result.Errors.Select(x => x.Description);
        return BadRequest(new RegisterResult { Successful = false, Errors = errors });
    }

    return Ok(new RegisterResult { Successful = true });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:54:03