如何在“剃刀页面”视图中显示角色列表?

时间:2018-10-11 08:03:25

标签: c# razor-pages selectlist

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

输入模型本身如下所示:

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" />
}

2 个答案:

答案 0 :(得分:2)

您可以执行以下步骤将列表加载到<select>标记帮助程序中:

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

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

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

2)使用LINQ List<string>将现有的Select属性转换为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();

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

<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>列表中),还应该删除RequiredAttribute属性的Roles,因为现在不需要该属性,并且可能会触发模型验证错误。

其他参考:The Select Tag Helper

答案 1 :(得分:1)

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

public List<SelectListItem> RolesItems 
public string Role

更多here