c# - 使用额外属性更新 AspNetUser 将不起作用
问题描述
晚上好。我被困在我似乎无法修复的事情上。我在我的项目中创建了一个名为 Address.cshtml.cs(模型)和 Address.cshtml(视图)的剃须刀页面,以便用户能够在注册后添加他们的用户信息。而且var result = await _userManager.UpdateAsync(user);
似乎不起作用。我尝试了两种方法在数据库中更新它:
第一次尝试
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AccountChange(UserModel model)
{
if (ModelState.IsValid)
{
// Get the current application user
var user = await _userManager.GetUserAsync(User);
//Update the details
user.name = model.name;
user.surname = model.surname;
user.street = model.street;
user.streetnumber = model.streetnumber;
user.city = model.city;
user.zipcode = model.zipcode;
// Update user address
var result = await _userManager.UpdateAsync(user);
}
//await _signInManager.RefreshSignInAsync(User);
_logger.LogInformation("User added their address information successfully.");
StatusMessage = "Your address information has been added.";
return RedirectToPage();
}
}
第二次尝试
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(UserModel model)
{
if (ModelState.IsValid)
{
UserModel u = await _userManager.FindByIdAsync(model.Id);
u.name = model.name;
u.surname = model.surname;
u.street = model.street;
u.streetnumber = model.streetnumber;
u.city = model.city;
u.zipcode = model.zipcode;
await _userManager.UpdateAsync(u);
return RedirectToAction("Index");
}
return RedirectToPage();
}
我怎样才能解决这个问题?我在下面添加了所有必要的代码。
地址.cshtml.cs
namespace bytme.Areas.Identity.Pages.Account.Manage
{
public class AddressModel : PageModel
{
private readonly UserManager<UserModel> _userManager;
private readonly SignInManager<UserModel> _signInManager;
private readonly ILogger<AddressModel> _logger;
public AddressModel(
UserManager<UserModel> userManager,
SignInManager<UserModel> signInManager,
ILogger<AddressModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
[BindProperty]
public InputModel Input { get; set; }
public string ReturnUrl { get; set; }
[TempData]
public string StatusMessage { get; set; }
public class InputModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "Name")]
[StringLength(100, ErrorMessage = "Invalid input. Maximum is 100 characters.")]
public string name { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Surname")]
[StringLength(100, ErrorMessage = "Invalid input. Maximum is 100 characters.")]
public string surname { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Street")]
[StringLength(48, ErrorMessage = "The longest street name in the Netherlands is 48 characters.")]
public string street { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "House Number")]
[StringLength(5, ErrorMessage = "The longest house number in the Netherlands is 5 characters.")]
public string streetnumber { get; set; }
//[DataType(DataType.Text)]
//[Display(Name = "House Number Addition", Description = "For example A or II")]
//[StringLength(6, ErrorMessage = "
//public string streetnumberadd { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "City")]
[StringLength(28, ErrorMessage = "The longest place name in the Netherlands is 28 characters.")]
public string city { get; set; }
[Required]
[DataType(DataType.PostalCode)]
[Display(Name = "Postal Code")]
[RegularExpression(@"^[1-9][0-9]{3}\s?[a-zA-Z]{2}$", ErrorMessage = "Invalid zip, for example: 1234AB")]
public string zipcode { get; set; }
}
public void OnGet(string returnUrl = null)
{
ReturnUrl = returnUrl;
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AccountChange(UserModel model)
{
if (ModelState.IsValid)
{
// Get the current application user
var user = await _userManager.GetUserAsync(User);
//Update the details
user.name = model.name;
user.surname = model.surname;
user.street = model.street;
user.streetnumber = model.streetnumber;
user.city = model.city;
user.zipcode = model.zipcode;
// Update user address
var result = await _userManager.UpdateAsync(user);
}
//await _signInManager.RefreshSignInAsync(User);
_logger.LogInformation("User added their address information successfully.");
StatusMessage = "Your address information has been added.";
return RedirectToPage();
}
}
}
地址.cshtml
@page
@model AddressModel
@inject SignInManager<UserModel> SignInManager
@using Microsoft.AspNetCore.Identity
@using bytme.Models;
@{
ViewData["Title"] = "Add Address Information";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@Html.Partial("_StatusMessage", Model.StatusMessage)
@{
var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<div>
<h3>Change your account settings</h3>
<hr />
<div class="row">
<div class="col-md-3">
<partial name="_ManageNav" />
</div>
<div class="col-md-9">
<div class="row">
<div class="col-md-6">
<h4>@ViewData["Title"]</h4>
<form id="change-password-form" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<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.surname"></label>
<input asp-for="Input.surname" class="form-control" />
<span asp-validation-for="Input.surname" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.street"></label>
<input asp-for="Input.street" class="form-control" />
<span asp-validation-for="Input.street" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.streetnumber"></label>
<input asp-for="Input.streetnumber" class="form-control" />
<span asp-validation-for="Input.streetnumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.city"></label>
<input asp-for="Input.city" class="form-control" />
<span asp-validation-for="Input.city" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.zipcode"></label>
<input asp-for="Input.zipcode" class="form-control" />
<span asp-validation-for="Input.zipcode" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
用户模型.cs
namespace bytme.Models
{
public class UserModel : IdentityUser
{
public override string Id { get; set; }
public override string Email { get; set; }
public override string UserName { get; set; }
public override string PasswordHash { get; set; }
public string zipcode { get; set; }
public string city { get; set; }
public string street { get; set; }
public string streetnumber { get; set; }
public string name { get; set; }
public string surname { get; set; }
}
}
ApplicationDbContext.cs
namespace bytme.Data
{
public class ApplicationDbContext : IdentityDbContext<UserModel>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
public DbSet<bytme.Models.Item> Items { get; set; }
public DbSet<bytme.Models.ItemCategories> ItemCategories { get; set; }
public DbSet<bytme.Models.UserModel> UserModels { get; set; }
public DbSet<bytme.Models.OrderHistory> OrderHistories { get; set; }
public DbSet<bytme.Models.OrderMain> OrderMains { get; set; }
public DbSet<bytme.Models.OrderStatus> OrderStatuses { get; set; }
public DbSet<bytme.Models.WishlistModel> WishlistModels { get; set; }
public DbSet<bytme.Models.ShoppingCartModel> ShoppingCartModels { get; set; }
}
}
解决方案
检查代码后,我发现了几个问题。
1.我对你的发帖方式有疑问AccountChange
。应遵循以下约定。根据 Microsoft docs about razor pages,生成了几个默认方法处理程序,例如:OnGet
OnPost
OnGetAsync
OnPostAsync
等。
但是,如果您想使用自定义处理程序名称,它也必须遵循一些命名约定。
方法应以
OnPost[Get,...]<Handlername>[Async|NoAsync](its optional)
.所以你的方法应该被命名为
OnPostAccountChangeAsync()
如果你定义了这样一个方法,你必须告诉一个视图,你想使用指定的处理程序。你用指令告诉它asp-page-handler
,所以你的表单应该是这样的:
<form id="change-password-form" method="post">
//...
<button type="submit" class="btn btn-default" asp-page-handler="AccountChange">Submit</button>
</form>
2.您正在绑定您的财产Input
[BindProperty]
public InputModel Input { get; set; }
但是,在您的方法OnPostAccountChangeAsync()
中,您尝试访问 type 的参数实例UserModel
,该实例将为 null。它没有绑定。在好的情况下,您将得到一个空异常。在糟糕的情况下,您将使用空属性更新您的实体。所以你的方法OnPostAccountChangeAsync()
应该接受参数实例,InputModel
或者你可以直接在方法体内访问这个属性(你可以去掉参数)
OnPostAccountChangeAsync(InputModel Input)
{
//...
}
3.它的小事,但是,它提高了你的代码的可读性。请在命名变量时保持一致。一致性使您的代码有更好的方向性。在 Csharp 中,属性应该以大写字母(PascalCasing)开头。不要犹豫,检查C# 命名约定
对于您在评论部分关于 UserManager 的问题:
您可以将Identity
其视为 wrapper (而不是说 api),它为用户管理提供了有用的方法,此外它还提供了其他东西。正如我所说,如果你查看你的包依赖,你可以发现它Entity Framework
是在Identity
nuget 包中发货的。这是什么意思?它让你有可能不仅仅依赖于一些“神秘的” Identity
。您可以清楚地使用Entity Framework
例如将新用户保存到表 AspNetUsers 中。明确地说,你不受限制。但是,如果您已经使用 Identity,最好使用它的可用方法。
推荐阅读
- amazon-web-services - AWS ECS Fargate 任务时区
- c# - 如何在网站上显示从监控摄像头系统接收的流媒体视频
- java - 在数组中获取重复数字时出现错误
- php - Laravel 迁移 (errno: 150 “外键约束格式不正确”)
- c++ - 获取引用参数的共享指针
- systemd - i3-nagbar 未从 systemd 服务执行(已设置显示和 xauthority)
- javascript - 错误,当使用 rehype-react 渲染 htmlAST
- css - 如何在颤振/飞镖中使用具有设定大小的自定义字体?
- php - 在用户之间共享文件
- visual-studio - LINQ to sql 类 LINQ to sql 对象?