Как правильно получить значения базы данных в пользовательском атрибуте для проверки IdentityRole? - PullRequest
0 голосов
/ 12 мая 2018

Я работаю над веб-приложением с несколькими ролями и пользователями.Я сделал это в .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(...);

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...