Я работаю над веб-приложением с несколькими ролями и пользователями.Я сделал это в .NET Core 2 со структурой учетных записей отдельных пользователей и опцией веб-приложения (не mvc, поэтому я использую MVVM с Razor Pages)
В настоящее время, когда я нажимаю кнопку «Изменить» дляПользователь, которого я отобразил в таблице данных / виде сетки, заполняет форму в том же виде всеми соответствующими значениями из базы данных, используя вызов AJAX в форме рядом с ним.
Он также заполняет раскрывающийся списокдля ролей это будет:
Заполненный выпадающий список
<label>Role</label>
<select class="form-control" id="roles" name="RoleId" asp-for="Input.RoleId">
<option value="Admin">User</option>
<option value="Manager">Manager</option>
<option value="User">User</option>
</select>
Моя входная модель
public class UsersModel : PageModel
{
...
private readonly ApplicationDbContext _dbContext;
public List<IdentityRole> Roles { get; set; }
public UsersModel(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<IactionResult> OnGet()
{
Roles = _dbContext.Roles.ToList();
}
public class UserModel
{
...
[Required]
[Display(Name = "Role")]
public string RoleId { get; set; }
...
}
}
Метод My Post
[ValidateAntiForgeryToken]
public async Task<IActionResult> OnPostEditAsync(UserModel model, string id)
{
...
var user = await _userManager.FindByIdAsync(id);
Task<IList<string>> rolesUser = _userManager.GetRolesAsync(user);
IdentityRole currentRole = await _roleManager.FindByNameAsync(rolesUser.Result.First());
string selectedRole = model.RoleId;
if (selectedRole != currentRole.Name)
{
await _userManager.RemoveFromRoleAsync(user, currentRole.Name);
await _userManager.AddToRoleAsync(user, selectedRole);
}
await _userManager.UpdateAsync(user);
return RedirectToPage(...);
...
}
Это работаетдолжным образом.Я могу нажать кнопку Сохранить, и все работает.Однако в этой ситуации возможно редактировать значение HTML с несуществующей ролью, например:
<option value="Not existing">Example</option>
, и оно немедленно вылетает.Поэтому я хотел бы проверить выбранную опцию на стороне сервера, чтобы избежать таких злонамеренных действий, как этот.
[RegularExpresson("^(Admin|Manager|User)*$)]
Это решает мою проблему, но жестко закодировано и кажется грязным.Я хотел бы сравнить это со значениями базы данных.Пользовательский атрибут должен сработать, но все приведенные примеры на других постах в этом случае не удовлетворяли моим потребностям.Все они показывают примеры MVC-шаблона, но не MVVM-шаблона.Я знаю, что это, вероятно, способ структурирования кода, но я не очень хорошо знаком с mvc, поэтому я не могу конвертировать эти примеры в моем контексте mvvm.
Попытка
Что я 'Мы уже пробовали:
Моя ViewModel
public class UserModel
{
...
[Required]
[CheckRole(typeof(IdentityRole))]
[Display(Name = "Role")]
public string RoleId { get; set; }
...
}
CheckRoleAttribute
public class CheckRoleAttribute : ValidationAttribute
{
public Type ObjectType { get; private set; }
public CheckRoleAttribute(Type type)
{
ObjectType = type;
}
protected override ValidationResult IsValid(
object value, ValidationContext validationContext)
{
// I understand passed value is the given option from the option to validate
// I'd like to obtain my available roles here that are available from the database, so I can validate it and return the correct error message.
}
}
Опять же, я использую MVVM-шаблон, а не MVC-шаблон.
редактировать 1
// My Attribute
protected override ValidationResult IsValid(
object value, ValidationContext validationContext)
{
var context = (ApplicationDbContext)validationContext.GetService(typeof(ApplicationDbContext));
if (!context.Roles.Any(p => p.Name == value)) // changed 'p => p' to 'p => p.Name'
{
return ValidationResult.Success;
}
return new ValidationResult($"The selected {value} doesn't exist.");
}
//My model
[Required]
[ValidateRole]
[Display(Name = "Role")]
public string RoleId { get; set; }
}
редактировать 2
[ValidateAntiForgeryToken]
public async Task<IActionResult> OnPostEditAsync(UserModel model, string id)
{
var user = await _userManager.FindByIdAsync(id);
Task<IList<string>> rolesUser = _userManager.GetRolesAsync(user);
IdentityRole currentRole = await _roleManager.FindByNameAsync(rolesUser.Result.First());
string selectedRole = model.RoleId;
if (user == null || !ModelState.IsValid)
{
return Page();
}
...
if (selectedRole != currentRole.Name)
{
await _userManager.RemoveFromRoleAsync(user, currentRole.Name);
await _userManager.AddToRoleAsync(user, selectedRole);
}
await _userManager.UpdateAsync(user);
return RedirectToPage(...);
}