asp.net mvc SelectList 的selected 失效及解决方案

本文解决了一个常见的ASP.NET MVC问题:当使用ViewData传递数据到视图并与DropdownListFor绑定时,如果ViewData的名字与字段名相同会导致错误。文章提供了避免这种冲突的方法。

ViewData 名 不能和 绑定的 DropdownListFor的字段名 重复

 

转载于:https://www.cnblogs.com/webenh/p/5733706.html

// Controllers/AdminController.cs using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; using UserManagementSystem.Web.Data; using UserManagementSystem.Web.Models; using UserManagementSystem.Web.Models.ViewModel; using UserManagementSystem.Web.Services; namespace UserManagementSystem.Web.Controllers; [Authorize(Roles = "Admin")] public class AdminController : Controller { private readonly UserManager<ApplicationUser> _userManager; private readonly ILogger<AdminController> _logger; private readonly ApplicationDbContext _context; // ✅ 必须注入 public AdminController(UserManager<ApplicationUser> userManager, ILogger<AdminController> logger,ApplicationDbContext context) { _userManager = userManager; _logger = logger; _context = context; } // GET: /Admin/Users public async Task<IActionResult> Users(string search, int page = 1, int pageSize = 10) { var query = _userManager.Users.AsQueryable(); if (!string.IsNullOrWhiteSpace(search)) { search = search.Trim(); query = query.Where(u => u.UserName.Contains(search) || u.Email.Contains(search) || u.RealName.Contains(search)); } var total = await query.CountAsync(); var users = await query .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); // ✅ 新增:获取每个用户的角色,并映射为显示名 var userRolesList = new List<(string UserId, List<string> DisplayNames)>(); foreach (var user in users) { var roles = await _userManager.GetRolesAsync(user); var displayNames = roles.Select(r => GetDisplayNameForRole(r)).ToList(); userRolesList.Add((user.Id, displayNames)); } ViewBag.Search = search; ViewBag.CurrentPage = page; ViewBag.PageSize = pageSize; ViewBag.TotalPages = (int)Math.Ceiling(total / (double)pageSize); ViewBag.UserRoles = userRolesList.ToDictionary(x => x.UserId, x => x.DisplayNames); // 存入 ViewBag return View(users); } // GET: /Admin/CreateUser public IActionResult CreateUser() { return View(); } // POST: /Admin/CreateUser [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> CreateUser(CreateUserViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = new ApplicationUser { UserName = model.Email, Email = model.Email, EmailConfirmed = true, RealName = model.Email.Split('@')[0], // 默认使用邮箱前缀作为真实姓名 CmbId = 0, // 默认村庄 IsActive = true }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { TempData["Success"] = $"用户 {user.Email} 创建成功。"; return RedirectToAction(nameof(Users)); } foreach (var error in result.Errors) { ModelState.AddModelError("", error.Description); } return View(model); } // GET: /Admin/EditUser/{id} public async Task<IActionResult> EditUser(string id) { var user = await _userManager.FindByIdAsync(id); if (user == null) return NotFound(); // 获取用户当前角色 var userRoles = await _userManager.GetRolesAsync(user); var model = new EditUserViewModel { Id = user.Id, UserName = user.UserName!, RealName = user.RealName ?? "", Email = user.Email!, PhoneNumber = user.PhoneNumber ?? "", CmbId = user.CmbId, IsActive = user.IsActive, SelectedRoles = userRoles.ToList() }; // ✅ 加载村庄选项 model.AvailableVillages = await _context.Cmbs .Select(c => new SelectListItem { Value = c.Id.ToString(), Text = c.Name }) .OrderBy(x => x.Text) .ToListAsync(); model.AvailableVillages.Insert(0, new SelectListItem { Value = "", Text = "-- 请选择村庄 --" }); // ✅ 加载所有角色用于下拉多选 var allRoles = await _context.Roles.Select(r => r.Name).ToListAsync(); model.AvailableRoles = allRoles.Select(roleName => new SelectListItem { Value = roleName, Text = GetDisplayNameForRole(roleName), Selected = userRoles.Contains(roleName) }).ToList(); return View(model); } // Controllers/AdminController.cs private string GetDisplayNameForRole(string role) { return role switch { "Admin" => "系统管理员", "User" => "普通用户", "Editor" => "内容编辑员", "Moderator" => "信息导入员", _ => char.ToUpper(role[0]) + role.Substring(1) // 首字母大写兜底 }; } // POST: /Admin/EditUser [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> EditUser(EditUserViewModel model) { if (!ModelState.IsValid) { // 需要重新填充 AvailableRoles 和 AvailableVillages await PopulateDropdowns(model); return View(model); } var user = await _userManager.FindByIdAsync(model.Id); if (user == null) return NotFound(); // 防止编辑关键账户 if (user.Email == "admin@example.com") { TempData["Error"] = "无法编辑系统管理员账户。"; return RedirectToAction(nameof(Users)); } // 更新用户基本信息 user.UserName = model.UserName; user.RealName = model.RealName; user.Email = model.Email; user.PhoneNumber = model.PhoneNumber; user.CmbId = model.CmbId ?? 1; user.IsActive = model.IsActive; var result = await _userManager.UpdateAsync(user); if (!result.Succeeded) { foreach (var error in result.Errors) ModelState.AddModelError("", error.Description); await PopulateDropdowns(model); return View(model); } // ✅ 处理角色更新 var oldRoles = await _userManager.GetRolesAsync(user); var newRoles = model.SelectedRoles ?? new List<string>(); // 移除不再拥有的角色 var rolesToRemove = oldRoles.Except(newRoles).ToList(); if (rolesToRemove.Any()) { var removeResult = await _userManager.RemoveFromRolesAsync(user, rolesToRemove); if (!removeResult.Succeeded) { AddErrors(removeResult); } } // 添加新增的角色 var rolesToAdd = newRoles.Except(oldRoles).ToList(); if (rolesToAdd.Any()) { var addResult = await _userManager.AddToRolesAsync(user, rolesToAdd); if (!addResult.Succeeded) { AddErrors(addResult); } } TempData["Success"] = $"用户信息及角色已更新:{user.Email}"; return RedirectToAction(nameof(Users)); } // 辅助方法:填充下拉项(避免重复代码) private async Task PopulateDropdowns(EditUserViewModel model) { model.AvailableVillages = await _context.Cmbs .Select(c => new SelectListItem { Value = c.Id.ToString(), Text = c.Name }) .OrderBy(x => x.Text) .ToListAsync(); model.AvailableVillages.Insert(0, new SelectListItem { Value = "", Text = "-- 请选择村庄 --" }); var allRoles = await _context.Roles.Select(r => r.Name).ToListAsync(); model.AvailableRoles = allRoles.Select(role => new SelectListItem { Value = role, Text = GetDisplayNameForRole(role), Selected = model.SelectedRoles?.Contains(role) ?? false }).ToList(); } // 辅助方法:添加错误到 ModelState private void AddErrors(IdentityResult result) { foreach (var error in result.Errors) { ModelState.AddModelError("", error.Description); } } // GET: /Admin/ResetPassword/{id} [HttpGet] public async Task<IActionResult> ResetPassword(string id) { var user = await _userManager.FindByIdAsync(id); if (user == null) return NotFound(); // 1. 生成密码重置 Token(安全令牌) var token = await _userManager.GeneratePasswordResetTokenAsync(user); // 2. 生成强密码 string newPassword = PasswordGenerator.GenerateRandomPassword(12); // 3. 使用 ResetPassword 直接重置(无需移除旧密码) var result = await _userManager.ResetPasswordAsync(user, token, newPassword); if (!result.Succeeded) { foreach (var error in result.Errors) { ModelState.AddModelError("", $"密码重置失败: {error.Description}"); } return View(new ResetPasswordViewModel { UserId = user.Id, UserName = user.UserName, GeneratedPassword = null }); } // 4. 刷新用户安全戳(强制所有旧 Token 失效) await _userManager.UpdateSecurityStampAsync(user); // 5. 成功 → 显示新密码 var model = new ResetPasswordViewModel { UserId = user.Id, UserName = user.UserName, GeneratedPassword = newPassword }; return View(model); } // POST: /Admin/ResetPassword [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model) { // 1. 验证模型 if (string.IsNullOrEmpty(model.NewPassword) || model.NewPassword != model.ConfirmPassword) { ModelState.AddModelError("", "密码为空或两次输入不一致。"); goto ReloadUser; } // 2. 查找用户(只查一次) var appUser = await _userManager.FindByIdAsync(model.UserId); if (appUser == null) { TempData["ErrorMessage"] = "用户不存在。"; return RedirectToAction(nameof(Users)); } // 3. 执行密码重置 var token = await _userManager.GeneratePasswordResetTokenAsync(appUser); var result = await _userManager.ResetPasswordAsync(appUser, token, model.NewPassword); if (result.Succeeded) { await _userManager.UpdateSecurityStampAsync(appUser); _logger.LogInformation("管理员重置了用户 {UserId} ({Email}) 的密码。", appUser.Id, appUser.Email); TempData["SuccessMessage"] = $"密码已成功重置为:{model.NewPassword}"; return RedirectToAction(nameof(Users)); } // 4. 如果失败,添加错误信息 foreach (var error in result.Errors) { ModelState.AddModelError("", $"密码重置失败: {error.Description}"); } ReloadUser: // 只有失败时才需要重新加载用户名 if (string.IsNullOrEmpty(model.UserName)) { var userToLoad = await _userManager.FindByIdAsync(model.UserId); if (userToLoad != null) { model.UserName = userToLoad.UserName; } } return View(model); } // POST: /Admin/DeleteUser/{id} [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> DeleteUser(string id) { var user = await _userManager.FindByIdAsync(id); if (user == null || user.Email == "admin@example.com") { TempData["Error"] = "无法删除此用户。"; return RedirectToAction(nameof(Users)); } var result = await _userManager.DeleteAsync(user); if (result.Succeeded) { TempData["Success"] = $"用户 {user.Email} 已被删除。"; } else { TempData["Error"] = "删除失败:" + string.Join(", ", result.Errors.Select(e => e.Description)); } return RedirectToAction(nameof(Users)); } } 这是我的admincontroller.cs,和// Controllers/AccountController.cs using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using UserManagementSystem.Web.Data; using UserManagementSystem.Web.Models; using UserManagementSystem.Web.Models.ViewModel; public class AccountController : Controller { private readonly UserManager<ApplicationUser> _userManager; private readonly ApplicationDbContext _context; public AccountController(UserManager<ApplicationUser> userManager, ApplicationDbContext context) { _userManager = userManager; _context = context; } [HttpGet] public IActionResult Register() { var model = new RegisterViewModel { Cmbs = _context.Cmbs.OrderBy(c => c.SortOrder).ToList() }; return View(model); } [HttpPost] public async Task<IActionResult> Register(RegisterViewModel model) { if (!ModelState.IsValid) return View(model); var user = new ApplicationUser { UserName = model.Email, Email = model.Email, RealName = model.RealName, CmbId = model.CmbId, IsVip = model.IsVip, IsActive = true }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { TempData["Success"] = "注册成功!"; return RedirectToAction("Users", "Admin"); } //foreach (var error in result.Errors) // ModelState.AddModelError("", error.Description); foreach (var error in result.Errors) { string zhError = error.Code switch { "DuplicateUserName" => $"用户名 '{model.Email}' 已被占用。", "InvalidUserName" => "用户名格式无效,请使用有效的邮箱地址。", "PasswordTooShort" => "密码太短,至少需要 6 位字符。", "PasswordRequiresDigit" => "密码必须包含至少一个数字(0-9)。", "PasswordRequiresLower" => "密码必须包含至少一个小写字母(a-z)。", "PasswordRequiresUpper" => "密码必须包含至少一个大写字母(A-Z)。", "PasswordRequiresNonAlphanumeric" => "密码必须包含至少一个特殊字符(如 !@#$%^&*)。", _ => $"注册失败:{error.Description}" }; ModelState.AddModelError(string.Empty, zhError); } model.Cmbs = _context.Cmbs.OrderBy(c => c.SortOrder).ToList(); return View(model); } } accountcontroller.cs 要求增加角色管理功能
10-21
// Controllers/AdminController.cs using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using UserManagementSystem.Web.Models; using UserManagementSystem.Web.Services; namespace UserManagementSystem.Web.Controllers; [Authorize(Roles = "Admin")] public class AdminController : Controller { private readonly UserManager<ApplicationUser> _userManager; private readonly ILogger<AdminController> _logger; public AdminController(UserManager<ApplicationUser> userManager, ILogger<AdminController> logger) { _userManager = userManager; _logger = logger; } // GET: /Admin/Users public async Task<IActionResult> Users(string search, int page = 1, int pageSize = 10) { var query = _userManager.Users.AsQueryable(); if (!string.IsNullOrWhiteSpace(search)) { search = search.Trim(); query = query.Where(u => u.UserName.Contains(search) || u.Email.Contains(search) || u.RealName.Contains(search)); } var total = await query.CountAsync(); var users = await query .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); ViewBag.Search = search; ViewBag.CurrentPage = page; ViewBag.PageSize = pageSize; ViewBag.TotalPages = (int)Math.Ceiling(total / (double)pageSize); return View(users); } // GET: /Admin/CreateUser public IActionResult CreateUser() { return View(); } // POST: /Admin/CreateUser [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> CreateUser(CreateUserViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = new ApplicationUser { UserName = model.Email, Email = model.Email, EmailConfirmed = true, RealName = model.Email.Split('@')[0], // 默认使用邮箱前缀作为真实姓名 CmbId = 0, // 默认村庄 IsActive = true }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { TempData["Success"] = $"用户 {user.Email} 创建成功。"; return RedirectToAction(nameof(Users)); } foreach (var error in result.Errors) { ModelState.AddModelError("", error.Description); } return View(model); } // GET: /Admin/EditUser/{id} public async Task<IActionResult> EditUser(string id) { var user = await _userManager.FindByIdAsync(id); if (user == null) return NotFound(); var model = new EditUserViewModel { Id = user.Id, UserName = user.UserName!, RealName = user.RealName ?? "", Email = user.Email!, PhoneNumber = user.PhoneNumber ?? "", CmbId = user.CmbId, IsActive = user.IsActive }; return View(model); } // POST: /Admin/EditUser [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> EditUser(EditUserViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = await _userManager.FindByIdAsync(model.Id.ToString()); if (user == null) return NotFound(); // 防止编辑关键系统账户 if (user.Email == "admin@example.com") { TempData["Error"] = "无法编辑系统管理员账户。"; return RedirectToAction(nameof(Users)); } // 更新所有可编辑字段 user.UserName = model.UserName; user.RealName = model.RealName; user.Email = model.Email; user.PhoneNumber = model.PhoneNumber; user.CmbId = model.CmbId; user.IsActive = model.IsActive; var result = await _userManager.UpdateAsync(user); if (result.Succeeded) { TempData["Success"] = $"用户信息已更新:{user.Email}"; return RedirectToAction(nameof(Users)); } foreach (var error in result.Errors) { ModelState.AddModelError("", error.Description); } return View(model); } // GET: /Admin/ResetPassword/{id} [HttpGet] public async Task<IActionResult> ResetPassword(string id) { var user = await _userManager.FindByIdAsync(id); if (user == null) return NotFound(); // 1. 生成密码重置 Token(安全令牌) var token = await _userManager.GeneratePasswordResetTokenAsync(user); // 2. 生成强密码 string newPassword = PasswordGenerator.GenerateRandomPassword(12); // 3. 使用 ResetPassword 直接重置(无需移除旧密码) var result = await _userManager.ResetPasswordAsync(user, token, newPassword); if (!result.Succeeded) { foreach (var error in result.Errors) { ModelState.AddModelError("", $"密码重置失败: {error.Description}"); } return View(new ResetPasswordViewModel { UserId = user.Id, UserName = user.UserName, GeneratedPassword = null }); } // 4. 刷新用户安全戳(强制所有旧 Token 失效) await _userManager.UpdateSecurityStampAsync(user); // 5. 成功 → 显示新密码 var model = new ResetPasswordViewModel { UserId = user.Id, UserName = user.UserName, GeneratedPassword = newPassword }; return View(model); } // POST: /Admin/ResetPassword [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model) { // 1. 验证模型 if (string.IsNullOrEmpty(model.NewPassword) || model.NewPassword != model.ConfirmPassword) { ModelState.AddModelError("", "密码为空或两次输入不一致。"); goto ReloadUser; } // 2. 查找用户(只查一次) var appUser = await _userManager.FindByIdAsync(model.UserId); if (appUser == null) { TempData["ErrorMessage"] = "用户不存在。"; return RedirectToAction(nameof(Users)); } // 3. 执行密码重置 var token = await _userManager.GeneratePasswordResetTokenAsync(appUser); var result = await _userManager.ResetPasswordAsync(appUser, token, model.NewPassword); if (result.Succeeded) { await _userManager.UpdateSecurityStampAsync(appUser); _logger.LogInformation("管理员重置了用户 {UserId} ({Email}) 的密码。", appUser.Id, appUser.Email); TempData["SuccessMessage"] = $"密码已成功重置为:{model.NewPassword}"; return RedirectToAction(nameof(Users)); } // 4. 如果失败,添加错误信息 foreach (var error in result.Errors) { ModelState.AddModelError("", $"密码重置失败: {error.Description}"); } ReloadUser: // 只有失败时才需要重新加载用户名 if (string.IsNullOrEmpty(model.UserName)) { var userToLoad = await _userManager.FindByIdAsync(model.UserId); if (userToLoad != null) { model.UserName = userToLoad.UserName; } } return View(model); } // POST: /Admin/DeleteUser/{id} [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> DeleteUser(string id) { var user = await _userManager.FindByIdAsync(id); if (user == null || user.Email == "admin@example.com") { TempData["Error"] = "无法删除此用户。"; return RedirectToAction(nameof(Users)); } var result = await _userManager.DeleteAsync(user); if (result.Succeeded) { TempData["Success"] = $"用户 {user.Email} 已被删除。"; } else { TempData["Error"] = "删除失败:" + string.Join(", ", result.Errors.Select(e => e.Description)); } return RedirectToAction(nameof(Users)); } } 将我这个代码中使用的Village,修改为Cmb
10-05
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值