ASP .NET Core Identity - 如何更新用户的个人信息?
ASP .NET Core Identity - how to update user's single detail?
我有一个关于在我的 ASP.NET Identity 应用程序中更新指定用户数据的问题。我有一个模型,它定义了创建、删除和更新用户的属性以及一个控制器。在控制器中,我有一个方法 public async Task<IActionResult> EditRole(string id)
可以编辑选定用户的详细信息。数据仅针对以下情况更新:
-更新所有数据
- 仅更新电子邮件
-用电子邮件更新至少一个值
当我尝试更新电子邮件以外的内容时,class CustomUserValidator
出现异常,它负责在创建帐户时验证用户的详细信息。
异常消息是 System.NullReferenceException: „Object reference not set to an instance of an object.” Microsoft.AspNetCore.Identity.IdentityUser<TKey>.Email.get returned null.
以下是需要查看的详细信息:
型号UserModel.cs:
using UserApp.Models;
using System.ComponentModel.DataAnnotations;
namespace UserApp
{
public class EditUserModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
}
控制器 AdminController.cs :
using UserApp.Database;
using UserApp.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace UserApp.Controllers
{
[Authorize(Roles = "Administrator")]
public class AdminController : Controller
{
private readonly UserManager<UserEntity> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public AdminController(UserManager<UserEntity> userManager, RoleManager<IdentityRole> roleManager)
{
this._userManager = userManager;
this._roleManager = roleManager;
}
//Views
public IActionResult EditUser() => View();
[HttpPost]
public async Task<IActionResult> EditUser(EditUserModel editUserModel,string id)
{
var user = await _userManager.FindByIdAsync(id);
if (user != null)
{
user.FirstName = editUserModel.FirstName;
user.LastName = editUserModel.LastName;
user.Email = editUserModel.Email;
var result = await _userManager.UpdateAsync(user);
if (result.Succeeded)
{
return RedirectToAction("Account");
}
else
{
AddErrorsFromResult(result);
}
}
else
{
ModelState.AddModelError("", "User not existing");
}
return View("Account", _userManager.Users);
}
}
查看 EditUser.cshtml :
@model EditUserModel
@{
Layout = "_Layout";
}
<h1>User update</h1>
<div asp-validation-summary="All" class="text-danger"></div>
<div class="row-edit">
<form asp-action="EditUser" method="post">
<p>First Name</p>
<input class="register form-control" asp-for="FirstName" />
<p>Last Name</p>
<input class="register form-control" asp-for="LastName" />
<p>Email</p>
<input class="register form-control" asp-for="Email" />
<br />
<input type="submit" value="Save" class="btn btn-primary" />
@* @foreach (var role in Model.RoleModel.Role)
{
<table>
<tr>
<td>@role.Name</td>
</tr>
</table>
}*@
</form>
</div>
CustomUserValidator.cs
using UserApp.Database;
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace UserApp.Infrastructure
{
public class CustomUserValidator : UserValidator<UserEntity>
{
public override async Task<IdentityResult> ValidateAsync(UserManager<UserEntity> manager, UserEntity user)
{
IdentityResult result = await base.ValidateAsync(manager, user);
List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
List<string> domain = new();
string[] domains = { "@tvp.pl", "@edu.co.uk"};
domain.AddRange(domains);
int addError = 0;
foreach(var check in domain) if(!user.Email.ToLower().EndsWith(check)) addError++;
if(addError == domain.Count)
{
errors.Add(new IdentityError
{
Code = "EmailDomainError",
Description = "Invalid email domain"
});
}
return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
}
}
}
您收到错误消息,因为您无法取消电子邮件字段。您应该做的是首先在 EditUser
的 GET 操作中填充视图模型,然后将其传递到表单所在的视图中。
因此请将您的 EditUser()
GET 操作更新为:
public async Task<IActionResult> EditUser()
{
string userId = <insert logic to get user's ID>
var user = await _userManager.FindByIdAsync(userId);
var viewModel = new EditUserModel
{
FirstName = user.FirstName,
LastName = user.LastName,
Email = user.Email
};
return View(viewModel);
}
这样用户将能够看到他们当前的电子邮件和姓名,并且他们可以选择修改他们想要的任何字段。
您当然不能相信用户不会取消电子邮件字段,因此您应该在视图模型中通过数据注释添加服务器端验证:
using UserApp.Models;
using System.ComponentModel.DataAnnotations;
namespace UserApp
{
public class EditUserModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
[Required]
public string Email { get; set; }
public string Password { get; set; }
}
}
然后在执行 任何操作之前检查 POST 操作中的模型状态 else:
if (!ModelState.IsValid)
{
return View();
}
如果您关心惯例,我建议您指定一个仅用于更新电子邮件的表单。大多数 applications/websites 都是这样做的。您可能应该在更新之前生成一个令牌。
我有一个关于在我的 ASP.NET Identity 应用程序中更新指定用户数据的问题。我有一个模型,它定义了创建、删除和更新用户的属性以及一个控制器。在控制器中,我有一个方法 public async Task<IActionResult> EditRole(string id)
可以编辑选定用户的详细信息。数据仅针对以下情况更新:
-更新所有数据
- 仅更新电子邮件
-用电子邮件更新至少一个值
当我尝试更新电子邮件以外的内容时,class CustomUserValidator
出现异常,它负责在创建帐户时验证用户的详细信息。
异常消息是 System.NullReferenceException: „Object reference not set to an instance of an object.” Microsoft.AspNetCore.Identity.IdentityUser<TKey>.Email.get returned null.
以下是需要查看的详细信息:
型号UserModel.cs:
using UserApp.Models;
using System.ComponentModel.DataAnnotations;
namespace UserApp
{
public class EditUserModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
}
控制器 AdminController.cs :
using UserApp.Database;
using UserApp.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace UserApp.Controllers
{
[Authorize(Roles = "Administrator")]
public class AdminController : Controller
{
private readonly UserManager<UserEntity> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public AdminController(UserManager<UserEntity> userManager, RoleManager<IdentityRole> roleManager)
{
this._userManager = userManager;
this._roleManager = roleManager;
}
//Views
public IActionResult EditUser() => View();
[HttpPost]
public async Task<IActionResult> EditUser(EditUserModel editUserModel,string id)
{
var user = await _userManager.FindByIdAsync(id);
if (user != null)
{
user.FirstName = editUserModel.FirstName;
user.LastName = editUserModel.LastName;
user.Email = editUserModel.Email;
var result = await _userManager.UpdateAsync(user);
if (result.Succeeded)
{
return RedirectToAction("Account");
}
else
{
AddErrorsFromResult(result);
}
}
else
{
ModelState.AddModelError("", "User not existing");
}
return View("Account", _userManager.Users);
}
}
查看 EditUser.cshtml :
@model EditUserModel
@{
Layout = "_Layout";
}
<h1>User update</h1>
<div asp-validation-summary="All" class="text-danger"></div>
<div class="row-edit">
<form asp-action="EditUser" method="post">
<p>First Name</p>
<input class="register form-control" asp-for="FirstName" />
<p>Last Name</p>
<input class="register form-control" asp-for="LastName" />
<p>Email</p>
<input class="register form-control" asp-for="Email" />
<br />
<input type="submit" value="Save" class="btn btn-primary" />
@* @foreach (var role in Model.RoleModel.Role)
{
<table>
<tr>
<td>@role.Name</td>
</tr>
</table>
}*@
</form>
</div>
CustomUserValidator.cs
using UserApp.Database;
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace UserApp.Infrastructure
{
public class CustomUserValidator : UserValidator<UserEntity>
{
public override async Task<IdentityResult> ValidateAsync(UserManager<UserEntity> manager, UserEntity user)
{
IdentityResult result = await base.ValidateAsync(manager, user);
List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
List<string> domain = new();
string[] domains = { "@tvp.pl", "@edu.co.uk"};
domain.AddRange(domains);
int addError = 0;
foreach(var check in domain) if(!user.Email.ToLower().EndsWith(check)) addError++;
if(addError == domain.Count)
{
errors.Add(new IdentityError
{
Code = "EmailDomainError",
Description = "Invalid email domain"
});
}
return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
}
}
}
您收到错误消息,因为您无法取消电子邮件字段。您应该做的是首先在 EditUser
的 GET 操作中填充视图模型,然后将其传递到表单所在的视图中。
因此请将您的 EditUser()
GET 操作更新为:
public async Task<IActionResult> EditUser()
{
string userId = <insert logic to get user's ID>
var user = await _userManager.FindByIdAsync(userId);
var viewModel = new EditUserModel
{
FirstName = user.FirstName,
LastName = user.LastName,
Email = user.Email
};
return View(viewModel);
}
这样用户将能够看到他们当前的电子邮件和姓名,并且他们可以选择修改他们想要的任何字段。
您当然不能相信用户不会取消电子邮件字段,因此您应该在视图模型中通过数据注释添加服务器端验证:
using UserApp.Models;
using System.ComponentModel.DataAnnotations;
namespace UserApp
{
public class EditUserModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
[Required]
public string Email { get; set; }
public string Password { get; set; }
}
}
然后在执行 任何操作之前检查 POST 操作中的模型状态 else:
if (!ModelState.IsValid)
{
return View();
}
如果您关心惯例,我建议您指定一个仅用于更新电子邮件的表单。大多数 applications/websites 都是这样做的。您可能应该在更新之前生成一个令牌。