【问题标题】:Updating AspNetUsers with extra properties won't work使用额外属性更新 AspNetUser 将不起作用
【发布时间】:2019-03-24 13:46:36
【问题描述】:

晚安。我被困在我似乎无法修复的事情上。我在我的项目中创建了一个名为 Address.cshtml.cs(模型)和 Address.cshtml(视图)的剃须刀页面,以便用户能够在 AFTER 注册后添加他们的用户信息。而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();
}

我该如何解决这个问题?我已经在下面添加了所有必要的代码。

Address.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();

        }
    }
}

Address.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" />
}

UserModel.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; }
    }
}

【问题讨论】:

  • 有什么特别的错误还是没有更新?
  • @ZiaulKabirFahad 嗨。它没有更新,没有任何错误。
  • @floorvmt 两件事,我查到了下面的信息If you leave any of the fields for ApplicationUser OR IdentityUser null the update will come back as successful but wont save the data in the database. 你确定,在方法中传递的实例是可以的,没有空属性?另外,关于 dbContext 可能存在的问题的很好的讨论,请查看最佳答案 link。第二件事,您不想尝试在没有 userManager 的情况下更新用户吗? ASP.Net Identity 依赖于 EF(继续)
  • @floorvmt(继续)所以您可以创建 new dbContext,将您的实体附加到 UserModel 集,将实体状态设置为已修改和 SaveChanges()。另外,我认为存在 som 扩展方法InsertOrUpdate()。至少值得测试。
  • @Arsiwaldi 哦,是的,我在 Postgres 中看到我要更新的每个属性都已设置为 null,我是否必须在模型中将其设置为“NOT NULL”或类似的东西?

标签: c# asp.net asp.net-mvc razor model-view-controller


【解决方案1】:

查看代码后,发现了几个问题。

1.我对你的发帖方式AccountChange有疑问。应遵循以下约定。根据有关剃刀页面的 Microsoft 文档,生成了几个默认方法处理程序,例如:OnGetOnPostOnGetAsyncOnPostAsync 等。

但是,如果您想使用 自定义处理程序name,它也必须遵循一些命名约定。

方法应该以 OnPost[Get,...]&lt;Handlername&gt;[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() 中,您尝试访问UserModel 类型的参数实例,该实例将为空。它没有绑定。在好的情况下,您将得到一个空异常。在糟糕的情况下,您将使用空属性更新您的实体。所以你的方法OnPostAccountChangeAsync()应该接受InputModel的参数实例,或者你可以直接在方法体内访问这个属性(你可以去掉参数)

OnPostAccountChangeAsync(InputModel Input)
{
 //...
}


3. 不过,这只是一件小事,它提高了代码的可读性。请在命名变量时保持一致。一致性使您的代码有更好的方向性。在 Csharp 中,属性应该以大写字母 (PascalCasing) 开头。不要犹豫,检查C# naming convention


关于评论部分关于 UserManager 的问题:
您可以将Identity 视为包装器(更确切地说是api),它为用户管理提供了有用的方法,此外它还提供了其他东西。正如我所说,如果你查看你的包依赖,你会发现Entity Framework 是在Identity nuget 包中发货的。这是什么意思?它让你有可能不仅仅依赖于一些“神秘的”Identity。您可以清楚地使用Entity Framework,例如将新用户保存到表 AspNetUsers 中。明确地说,你不受限制。但是,如果您已经使用 Identity,最好使用它的可用方法。

【讨论】:

  • 感谢您回答@Arsiwaldi。但它仍然对我不起作用。当我让他们在注册时添加信息时,添加信息确实有效。虽然,这不是我想要的.. 我为它提出了一个新问题.. stackoverflow.com/questions/52906582/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多