如何在 Razor 页面视图中显示角色列表?

how can i display a list of roles in Razor Pages view?

我正在尝试将 asp.net 核心 Web 应用程序中的角色列表添加到 Razor 页面,但我不确定如何执行此操作。我希望用户能够选择要注册的新用户的角色。

输入模型本身如下所示:

public class InputModel
    {

        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Payroll")]
        [DataType(DataType.Text)]
        public string Payroll { get; set; }

        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        public List<String> Roles { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

如下所示,我目前在我的视图中有硬编码值(摘录):

<div class="form-group">
            <label asp-for="Input.Roles"></label>
            <select asp-for="Input.Roles" class="form-control">
                <option value="Administrator">Administrator</option>
                <option value="NormalUser" selected>NormalUser</option>
            </select>
        </div>

这适用于我想要它做的事情,但我想用我的应用程序中的动态角色列表替换它。

我的 OnGet() 方法中有以下内容

var roles = _roleManager.Roles.Select(x => x.Name).ToList();
InputModel vm = new InputModel();
vm.Roles = roles;
ReturnUrl = returnUrl;

我想问的是如何将角色列表变成我可以在页面本身上使用的形状。

谢谢。

编辑...后面的完整代码:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using MailTracker.Models;

namespace MailTracker.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class RegisterModel : PageModel
{
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<IdentityRole> _roleManager;
    private readonly ILogger<RegisterModel> _logger;
    private readonly IEmailSender _emailSender;

    public RegisterModel(
        UserManager<ApplicationUser> userManager,
        RoleManager<IdentityRole> roleManager,
        SignInManager<ApplicationUser> signInManager,
        ILogger<RegisterModel> logger,
        IEmailSender emailSender)
    {
        _userManager = userManager;
        _roleManager = roleManager;
        _signInManager = signInManager;
        _logger = logger;
        _emailSender = emailSender;
    }

    [BindProperty]
    public InputModel Input { get; set; }

    public string ReturnUrl { get; set; }

    public class InputModel
    {

        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Full name")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Payroll")]
        [DataType(DataType.Text)]
        public string Payroll { get; set; }

        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        public List<SelectListItem> RoleList { get; set; }

        public string SelectedRole { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

    public void OnGet(string returnUrl = null)
    {
        var roles = _roleManager.Roles.Select(x => x.Name).ToList();
        InputModel vm = new InputModel
        {
            RoleList = roles.Select(x => new SelectListItem { Text = x, Value = x }).ToList()
        };
        ReturnUrl = returnUrl;
    }

    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser {
                UserName = Input.Email,
                Email = Input.Email,
                Name = Input.Name,
                Payroll = Input.Payroll
            };

            string role = Input.SelectedRole;

            var result = await _userManager.CreateAsync(user, Input.Password);
            if (result.Succeeded)
            {
                _logger.LogInformation("User created a new account with password.");

                //add default NormalUser role to user




                await _userManager.AddToRoleAsync(user, role);

                //

                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { userId = user.Id, code = code },
                    protocol: Request.Scheme);

                await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }

        // If we got this far, something failed, redisplay form
        return Page();
    }
}

}

以及整个页面本身:

@page
@model RegisterModel
@{
    ViewData["Title"] = "Register";
}

<h2>@ViewData["Title"]</h2>

<div class="row">
    <div class="col-md-4">
        <form asp-route-returnUrl="@Model.ReturnUrl" method="post">
            <h4>Create a new account.</h4>
            <hr />

            <div class="form-group">
                <label asp-for="Input.Name"></label>
                <input asp-for="Input.Name" class="form-control" />
                <span asp-validation-for="Input.Name" class="text-danger"></span>
            </div>

            <div class="form-group">
                <label asp-for="Input.Payroll"></label>
                <input asp-for="Input.Payroll" class="form-control" />
                <span asp-validation-for="Input.Payroll" class="text-danger"></span>
            </div>

            <div class="form-group">
                <label asp-for="Input.RoleList"></label>
                <select asp-for="Input.SelectedRole" asp-items="Model.Input.RoleList" class="form-control"></select>
            </div>

            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Input.Email"></label>
                <input asp-for="Input.Email" class="form-control" />
                <span asp-validation-for="Input.Email" class="text-danger"></span>
            </div>

            <div class="form-group">
                <label asp-for="Input.Password"></label>
                <input asp-for="Input.Password" class="form-control" />
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.ConfirmPassword"></label>
                <input asp-for="Input.ConfirmPassword" class="form-control" />
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-default">Register</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

这样做:<select asp-for="Role" asp-items="Model.RolesItems"></select>

public List<SelectListItem> RolesItems 
public string Role

更多here

您可以执行以下步骤将列表加载到 <select> 标签助手:

1) 在视图模型中创建一个 List<SelectListItem> 属性(例如 InputModel)和一个 string 属性 来保存选定的值。

[Required]
public string SelectedRole { get; set; }

public List<SelectListItem> RoleList { get; set; }

2) 使用 LINQ Select 将现有 List<string> 属性 转换为 List<SelectListItem> 对象并将其分配给 RoleList 属性。

vm.RoleList = vm.Roles.Select(x => new SelectListItem { Text = x, Value = x }).ToList();

3) 最后,使用 asp-items 标签助手将其绑定到 <select> 元素中:

<select asp-for="Input.SelectedRole" asp-items="Input.RoleList" class="form-control"></select>

更新:

作为替代方案,您可以将 List<SelectListItem> 添加为 PageModel 属性 以及表达式主体成员:

public List<SelectListItem> RoleList => vm.Roles.Select(x => new SelectListItem { Text = x, Value = x }).ToList();

并为 asp-items 属性设置 Model.RoleList

<select asp-for="Input.SelectedRole" asp-items="Model.RoleList" class="form-control"></select>

如果您不想添加 List<SelectListItem> 属性,您可以使用 ViewData 分配选项列表:

ViewData["RoleList"] = vm.Roles.Select(x => new SelectListItem { Text = x, Value = x }).ToList();

并像这样绑定到页面:

<select asp-for="Input.SelectedRole" asp-items="@((List<SelectListItem>)ViewData["RoleList"])"></select>

<option> 标签将自动创建,无需再对其进行硬编码。

注意: 避免将 List<string> 直接绑定到 asp-for 属性,因为 asp-for 用于 <select> 标记旨在具有单个值(即从 <option> 列表中选择的值),您还应该为 Roles 属性 删除 RequiredAttribute,因为该属性现在是不必要的,可能会触发模型验证错误。

附加参考:The Select Tag Helper