.net5 core Razor项目实战系列之九:用户管理功能的实现 (新增、修改用户)
本篇介绍用户的新增和修改,对于很多业务对象来说,新增和修改的用户界面是非常相似的,
在设计的时候可以将这两个功能写到一个页面,调用方在打开这个页面的时候传递一个参数来区分是做新增还是修改,
比如可以传递一个mode参数,当mode=1时表示新增,mode=2时表示修改,或者用这个对象的id来区分,
id=0时表示新增,id>0时表示修改,这里我们用第二种方式来实现(见上篇文章),如下:
在/Auth目录下新增UserEdit.cshtml页面,不使用布局页,如下:
UserEdit.cshtml页面代码如下:
@page @model AuthManagement.Pages.Auth.UserEditModel @using AuthManagement.DbUtil.Entity; @{ Layout = null;//不使用布局页只需将Layout属性设置成null就可以了 } <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>编辑用户信息</title> <style> .tr1 {height: 40px; border: solid 1px #c0c0c0;} .td1 {font-size: 15px;} .input1 {width: 240px; height: 32px; font-size: 15px;} </style> </head> <body> <form method="post"> <input class="input1" type="hidden" name="userid" value="@Model.Tuser.UserId" /> <!--在部门下拉框的 onchange 事件中给部门名称赋值,这样Post后可以将值映射到TUser对象的DeptName上--> <input class="input1" type="hidden" id="deptname" name="deptname" value="@Model.Tuser.DeptName" /> <table style="width:400px;border-collapse: collapse;border: solid 1px #c0c0c0;"> <tr style="background-color:antiquewhite;height:40px;"> <td> @Model.EditType</td> </tr> <tr class="tr1"> <td class="td1"> 用户姓名: <input class="input1" type="text" size="25" maxlength="10" name="username" value="@Model.Tuser.UserName" /> </td> </tr> <tr class="tr1"> <td class="td1"> 联系电话: <input class="input1" type="text" size="25" maxlength="10" name="mobile" value="@Model.Tuser.Mobile" /> </td> </tr> <tr class="tr1"> <td class="td1"> 所属部门: <select name="deptid" class="input1" onchange="javascript:document.getElementById('deptname').value = this.options[this.options.selectedIndex].text;"> @foreach (TDept dept in Model.DeptList) { if (dept.DeptId == @Model.Tuser.DeptId) { <option value="@dept.DeptId" selected="selected">@dept.DeptName</option> } else { <option value="@dept.DeptId">@dept.DeptName</option> } } </select> </td> </tr> <tr class="tr1"> <td class="td1"> 登录帐号: <input class="input1" type="text" size="25" maxlength="10" name="signinacc" value="@Model.Tuser.SigninAcc" /> </td> </tr> <tr class="tr1"> <td class="td1"> 登录密码: <input class="input1" type="text" size="25" maxlength="10" name="signpwd" value="@Model.Tuser.SignPwd" /> </td> </tr> <tr class="tr1"> <td align="center"> <button type="submit">保存</button> <button onclick="javascript: window.close();">关闭</button> </td> </tr> </table> </form> </body> </html>
一般情况下,后台.cs文件接收页面Post过来的表单数据用 Request.Form["xxx"] 来取值,
有些时候表单中的控件比较多,可能有20、30个以上,这时用 Request.Form["xxx"] 一个一个取就比较低效了,
为此 .net core Razor 为我们提供了 [FromForm] 这个特性,在 OnPost() 方法中用 [FromForm] 去修饰形参中的对象,
系统会自动将表单中的值映射到形参对象的属性上,见如下红色部分代码 。
需要注意的是,用 [FromForm] 去修饰形参中对象的时候一定要确保表单中控件名称和和对象的属性名称相同,不区分大小写。
namespace AuthManagement.Pages.Auth { public class UserEditModel : PageModel { private readonly AuthDbContext _context; //构造函数中对 AuthDbContext 做依赖注入 public UserEditModel(AuthDbContext context) { _context = context; } public string EditType { get; set; }//定义页面标题取值 public List<TDept> DeptList { get; set; }//定义部门列表取值 public TUser Tuser { get; set; }//定义用户对象取值 private void InitEditType(int userId) { EditType = "新增用户"; if (userId > 0) { EditType = "修改用户"; } } private void InitDept() { //初始化页面的部门(下拉列表中的选项) DeptList = _context.TDepts.Where<TDept>(dept => dept.IsValid == 1).ToList<TDept>(); } private void InitUser(int userId) { Tuser = new TUser(); if (userId > 0) { Tuser = _context.TUsers.Find(userId);//如果是修改,初始化该用户的信息 } }
//点击超链接打开页面是GET方式,按约定执行OnGet()方法 public void OnGet() { string userId = Request.Query["userid"]; int uid = Convert.ToInt32(userId); InitEditType(uid); InitDept(); InitUser(uid); } //用户点保存按钮时执行,在form中不需要指定action, //按约定以Post方式提交的表单对应的方法是OnPost //这里的方法参数用 [FromForm] 修饰后可以自动将表单中控件的值赋给TUser对象中同名的属性,不区分大小写, //当字段比较多的时候,这种自动映射表单控件的值到对象属性上的方式让编码非常方便。 public void OnPost([FromForm] TUser user) { string userId = Request.Query["userid"]; if (int.TryParse(userId, out int uid)) { if (uid > 0) { user.ModifyTime = DateTime.Now;//表单中没有修改时间这个控件,所以要手动赋值。 ModifyUser(user); //user对象已经自动得到了表单中同名控件的值了(新增时也是一样的)。 } else { int newUserId = AddUser(user); userId = newUserId.ToString(); } } OnGet();//重新获取数据 //执行完之后让页面重新加载一下避免用户刷新的时候数据再次回传 Response.Redirect("/Auth/UserEdit?userid=" + userId); } private int AddUser(TUser user) { user.CreateTime = DateTime.Now; user.IsValid = 1; _context.TUsers.Add(user); _context.SaveChanges(); return user.UserId; } private void ModifyUser(TUser user) { //设置序列化时的对中文的编码方式,为后续系列化TUser对象写入TLog表做准备 JsonSerializerOptions options = new JsonSerializerOptions { Encoder = JavaScriptEncoder.Create(UnicodeRanges.All), }; List<TLog> logList = GenerateLog(); //初始化包含2条日志信息的列表 //先找出要更改的实体 TUser oldUser = _context.TUsers.Find(user.UserId); //将更改前的数据序列化成json后记录下来 logList[0].TableData = JsonSerializer.Serialize<TUser>(oldUser, options); //保存修改后的值到TUser对象中,这里赋值后执行_context.SaveChanges()方法就会将修改后的值写入数据库了。 oldUser.UserName = user.UserName;//用 [FromForm] 修饰后避免手写 Request.From["username"] 取值,非常方便。 oldUser.Mobile = user.Mobile; oldUser.ModifyTime = user.ModifyTime; oldUser.SigninAcc = user.SigninAcc; oldUser.SignPwd = user.SignPwd; oldUser.DeptId = user.DeptId; oldUser.DeptName = user.DeptName; //将更改后的数据序列化成json后记录下来 logList[1].TableData = JsonSerializer.Serialize<TUser>(oldUser, options); //保存数据到t_log表 _context.TLogs.AddRange(logList); //将更改保存到数据库 _context.SaveChanges(); } /// <summary> /// 将更改前和更改后的数据保存到t_log表 /// </summary> /// <returns></returns> private List<TLog> GenerateLog() { int userId = 0; string userName = "未知"; //取出登录时设置的用户信息 ClaimsPrincipal cp = HttpContext.User; if (cp.Identity.IsAuthenticated) { //取出登录时设置的所有用户信息 List<Claim> claims = cp.Claims.ToList<Claim>(); //通过传入Lambda表达式找出登录时设置的 UserId 值 string uid = claims.Single<Claim>(option => option.Type == "UserId").Value; userId = Convert.ToInt32(uid); //通过传入Lambda表达式找出登录时设置的 UserName 值 userName = claims.Single<Claim>(option => option.Type == "UserName").Value; } string batchNo = Guid.NewGuid().ToString(); TLog beforeLog = new TLog { UserId = userId, UserName = userName, BatchNo = batchNo, TableName = "t_user", TableData = "", LogTime = DateTime.Now }; TLog afterLog = new TLog { UserId = userId, UserName = userName, BatchNo = batchNo, TableName = "t_user", TableData = "", LogTime = DateTime.Now }; List<TLog> logList = new List<TLog>(); logList.Add(beforeLog); logList.Add(afterLog); return logList; } }
编译后运行画面如下(修改时):
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人