ASP.NET MVC独立用户账户扩展:关联自定义Customers表技术咨询
首先,不管是先创建MVC项目再添加身份,还是直接创建带身份的MVC项目,都能实现你的需求,但我更推荐直接创建带「独立用户账户」的MVC项目——因为Visual Studio会自动生成全套身份相关的控制器、视图和配置代码,你只需要在此基础上扩展,比事后手动添加身份要省心得多。
下面是具体的实现步骤,假设你已经创建了带独立身份的MVC项目,并且已经定义好Customer实体:
1. 完善实体关联
确保你的Customer模型和ApplicationUser(身份系统的用户模型)建立正确的关联:
// Customer.cs public class Customer { public int Id { get; set; } // 关联AspNetUsers表的外键(GUID格式的UserId) public string UserId { get; set; } // 你的自定义字段,比如姓名、电话等 public string FullName { get; set; } public string PhoneNumber { get; set; } // 导航属性,建立一对一关联 public virtual ApplicationUser User { get; set; } }
同时在ApplicationUser里添加反向导航属性(可选,但方便后续查询):
// ApplicationUser.cs public class ApplicationUser : IdentityUser { // 反向导航到Customer public virtual Customer Customer { get; set; } }
最后在ApplicationDbContext中添加Customer的DbSet:
// ApplicationDbContext.cs public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } // 添加Customer表的DbSet public DbSet<Customer> Customers { get; set; } }
2. 修改注册ViewModel和视图
找到身份系统的RegisterViewModel(通常在Models/AccountViewModels文件夹下),添加你需要的Customer字段:
// RegisterViewModel.cs public class RegisterViewModel { // 原有的字段 [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} 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; } // 新增的Customer字段 [Required] [Display(Name = "Full Name")] public string FullName { get; set; } [Required] [Display(Name = "Phone Number")] public string PhoneNumber { get; set; } }
然后修改注册视图Views/Account/Register.cshtml,添加这些字段的表单控件:
<div class="form-group"> <label asp-for="FullName" class="control-label"></label> <input asp-for="FullName" class="form-control" /> <span asp-validation-for="FullName" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="PhoneNumber" class="control-label"></label> <input asp-for="PhoneNumber" class="form-control" /> <span asp-validation-for="PhoneNumber" class="text-danger"></span> </div>
3. 修改注册逻辑,同步创建Customer记录
打开Controllers/AccountController.cs,找到Register的POST动作,在用户创建成功后添加Customer的创建逻辑:
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<IActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { // ********** 新增代码:创建Customer记录 ********** var customer = new Customer { UserId = user.Id, // 关联刚创建的用户ID FullName = model.FullName, PhoneNumber = model.PhoneNumber }; _context.Customers.Add(customer); await _context.SaveChangesAsync(); // *********************************************** await _signInManager.SignInAsync(user, isPersistent: false); _logger.LogInformation("User created a new account with password."); return RedirectToAction(nameof(HomeController.Index), "Home"); } AddErrors(result); } // If we got this far, something failed, redisplay form return View(model); }
可选:添加事务保证数据一致性
如果担心创建用户成功但创建Customer失败的情况,可以用事务包裹两个操作:
using (var transaction = await _context.Database.BeginTransactionAsync()) { try { var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { var customer = new Customer { UserId = user.Id, FullName = model.FullName, PhoneNumber = model.PhoneNumber }; _context.Customers.Add(customer); await _context.SaveChangesAsync(); await transaction.CommitAsync(); await _signInManager.SignInAsync(user, isPersistent: false); return RedirectToAction(nameof(HomeController.Index), "Home"); } AddErrors(result); } catch (Exception) { await transaction.RollbackAsync(); // 可以添加错误提示,告知用户注册失败 ModelState.AddModelError("", "Registration failed, please try again later."); } }
关于「先建MVC再添加身份」的疑问
老实说,这种方式反而更麻烦——因为你需要手动安装Identity相关的NuGet包、配置Startup.cs、添加身份控制器和视图,还要处理路由和权限配置,不如直接创建带身份的MVC项目高效。除非你有特殊需求(比如现有MVC项目需要新增身份功能),否则优先选择直接创建带独立用户账户的模板。
内容的提问来源于stack exchange,提问作者Stu

