我有以下注册方法,我发誓我(手动)在不久前对此进行了测试,并注意到如果用户名已经存在,则结果只是具有错误的结果值。成功,并将错误消息追加到模型状态(使用 AddErrors(result) 帮助程序方法中的生成)。我很确定这种方法(Register(...)
)开箱即用 ASP.NET mvc 5,但我想我更改了用户以包含用户名(而开箱即用,电子邮件只是用作用户名)。
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Username, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
相反,我目前收到错误作为实体验证错误被抛出和取消捕获。
我知道我可以简单地捕获此错误并继续我的一天,但是如果不是正确的行为,我想确保其他原因导致了此问题。
更新:
创建新的 MVC 项目后,我可以确认典型行为(注册重复用户名时)是 CreateAsync 应该返回一个结果值为 false 的结果。成功,并且应将错误消息"用户名已占用"附加到模型状态。显然,我的代码或配置中有些不对劲,但我对从哪里开始探索一无所知。如果它有帮助,我最近在我的代码的其他地方看到了 EntityValidationErrors,在这种情况下也不应该保证它。请参阅:无法保存数据库更新上的更改。可能是奇怪的延迟加载行为?
我找到了自己的解决方案。正如我所提到的,我已经更改了用户以包含用户名(以及使电子邮件可选)。此任务的一部分涉及创建自定义用户验证程序类。在自定义用户验证器的 ValidateAsync 方法中,我忘记检查用户名是否已经存在(并且不属于用户)。这样:
async Task<IdentityResult> IIdentityValidator<TUser>.ValidateAsync(TUser item)
{
var errors = new List<string>();
// ...
// Piece of code I have now added
var owner = await _manager.FindByNameAsync(item.UserName);
if (owner != null && !EqualityComparer<string>.Default.Equals(owner.Id, item.Id))
{
errors.Add($"Username {item.UserName} is already taken");
}
// End of code I added
// ...
return errors.Any()
? IdentityResult.Failed(errors.ToArray())
: IdentityResult.Success;
}
我相信对我来说学到的教训是应用程序层验证之间的区别,其中验证由用户管理器在 CreateAsync 方法中进行。在应用程序层验证的情况下,错误将完全按照规定呈现。如果省略了该验证层,并且数据库面临相同的约束,则在保存上下文时,它将抛出自己的错误。在这种情况下,一个稍微更神秘的 EntityValidationError。