ASP.NET MVC中SQL数据编辑删除的QueryString与请求问题
我来帮你一步步搞定这两个问题,先从编辑功能的参数传递问题说起,再解决删除操作的POST请求需求:
问题1:修复EditUser的参数传递与视图数据填充
你遇到的Request.QueryString["Username"]报错,本质是在ASP.NET MVC中不需要这么复杂的写法——框架已经帮我们实现了自动参数绑定,直接在控制器方法里声明参数即可接收QueryString的值。
步骤1:修改HttpGet的EditUser方法,获取用户名并填充模型
把HomeController里的HttpGet EditUser改成这样,让它自动接收URL里的Username参数,同时从数据库获取用户当前角色,填充到模型中传给视图:
[HttpGet] public IActionResult EditUser(string username) { // 先从数据库获取用户当前的角色,用来在视图中默认选中 UsersDAL ud = new UsersDAL(); var existingUser = ud.GetUserByUsername(username); if (existingUser == null) { return NotFound(); // 如果用户不存在,返回404页面 } return View(existingUser); }
步骤2:在UsersDAL中新增查询用户的方法
需要添加一个方法来获取指定用户名的用户信息(主要是当前角色):
public Users GetUserByUsername(string username) { string connectionstring = "MY_CONNECTION_STRING"; // 使用SQL Server系统视图查询用户所属角色 string sql = @"SELECT dp.name AS Username, rp.name AS Role FROM sys.database_principals dp JOIN sys.database_role_members drm ON dp.principal_id = drm.member_principal_id JOIN sys.database_principals rp ON drm.role_principal_id = rp.principal_id WHERE dp.name = @Username"; using (SqlConnection conn = new SqlConnection(connectionstring)) { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddWithValue("@Username", username); conn.Open(); using (SqlDataReader reader = cmd.ExecuteReader()) { if (reader.Read()) { return new Users { Username = reader["Username"].ToString(), Role = reader["Role"].ToString() }; } return null; } } }
步骤3:修复EditUser视图的用户名输入框
你当前的用户名输入框手动设置了value="",而且disabled属性不影响模型绑定,直接用asp-for就能自动填充值:
<input asp-for="Username" type="text" class="form-control" id="username" name="Username" required disabled />
步骤4:修正Edit方法的逻辑(原逻辑无效)
你之前的Edit方法是先从同一个角色移除再添加,完全没有作用。正确逻辑是先从旧角色移除用户,再添加到新角色:
public void Edit(Users u, string oldRole) { string connectionstring = "MY_CONNECTION_STRING"; string sqlRemove = "ALTER ROLE @OldRole DROP MEMBER @Username"; string sqlAdd = "ALTER ROLE @NewRole ADD MEMBER @Username"; using (SqlConnection conn = new SqlConnection(connectionstring)) { conn.Open(); using (var transaction = conn.BeginTransaction()) { try { // 移除旧角色 SqlCommand cmdRemove = new SqlCommand(sqlRemove, conn, transaction); cmdRemove.Parameters.AddWithValue("@OldRole", oldRole); cmdRemove.Parameters.AddWithValue("@Username", u.Username); cmdRemove.ExecuteNonQuery(); // 添加新角色 SqlCommand cmdAdd = new SqlCommand(sqlAdd, conn, transaction); cmdAdd.Parameters.AddWithValue("@NewRole", u.Role); cmdAdd.Parameters.AddWithValue("@Username", u.Username); cmdAdd.ExecuteNonQuery(); transaction.Commit(); } catch { transaction.Rollback(); throw; // 抛出异常让控制器处理 } } } }
然后修改HttpPost EditUser方法,传递旧角色参数:
[HttpPost] public IActionResult EditUser(Users u) { if (!ModelState.IsValid) { // 验证失败时恢复用户原角色 UsersDAL ud = new UsersDAL(); var existingUser = ud.GetUserByUsername(u.Username); u.Role = existingUser.Role; return View(u); } UsersDAL ud = new UsersDAL(); var existingUser = ud.GetUserByUsername(u.Username); ud.Edit(u, existingUser.Role); return RedirectToAction("ShowUsers"); }
问题2:实现DeleteUser的POST请求(不跳转视图)
你当前用@Html.ActionLink生成的是GET请求,不符合REST规范(删除操作应该用POST/DELETE),这里提供两种实现方式:
方式1:表单同步提交(删除后跳转回列表)
把ShowUsers视图中的Delete链接改成表单,提交POST请求:
<td class="actions"> <form asp-controller="Home" asp-action="DeleteUser" method="post" onsubmit="return confirm('确定要删除该用户吗?');"> <input type="hidden" name="Username" value="@item.Username" /> <button type="submit" class="btn btn-link p-0">Delete</button> </form> </td>
然后修改控制器的DeleteUser方法,直接接收用户名参数:
[HttpPost] public IActionResult DeleteUser(string username) { if (string.IsNullOrEmpty(username)) { return BadRequest(); } UsersDAL ud = new UsersDAL(); ud.Delete(new Users { Username = username }); return RedirectToAction("ShowUsers"); }
方式2:AJAX异步删除(无页面跳转,实时移除行)
如果想要完全不跳转页面,用AJAX实现异步删除:
先修改ShowUsers视图中的Delete按钮:
<td class="actions"> <button class="btn btn-link p-0 delete-btn" data-username="@item.Username">Delete</button> </td>
然后在页面底部添加AJAX脚本(记得在视图顶部加@Html.AntiForgeryToken()来防CSRF):
@Html.AntiForgeryToken() <script> document.querySelectorAll('.delete-btn').forEach(btn => { btn.addEventListener('click', async function() { if (!confirm('确定要删除该用户吗?')) return; const username = this.dataset.username; const token = document.querySelector('input[name="__RequestVerificationToken"]').value; const response = await fetch('/Home/DeleteUser', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'RequestVerificationToken': token }, body: `Username=${encodeURIComponent(username)}` }); if (response.ok) { // 删除成功后移除当前行 this.closest('tr').remove(); } else { alert('删除失败,请重试'); } }); }); </script>
最后修改控制器的DeleteUser方法返回JSON:
[HttpPost] public IActionResult DeleteUser(string username) { if (string.IsNullOrEmpty(username)) { return Json(new { success = false, message = "用户名不能为空" }); } try { UsersDAL ud = new UsersDAL(); ud.Delete(new Users { Username = username }); return Json(new { success = true }); } catch (Exception ex) { return Json(new { success = false, message = ex.Message }); } }
额外注意事项
- 不要用
String.Format拼接SQL,这会导致SQL注入风险,全部改用参数化查询(就像上面的示例代码那样)。 - 数据库连接字符串建议放在配置文件中(
appsettings.json或Web.config),不要硬编码。 - 操作数据库时尽量用
using语句,自动释放连接资源。
内容的提问来源于stack exchange,提问作者0xburned

