【问题标题】:Updating user data - ASP.NET Identity更新用户数据 - ASP.NET 标识
【发布时间】:2013-12-24 23:48:40
【问题描述】:

我已将自定义字段添加到 ApplicationUser
我还创建了一个表单,用户可以通过该表单输入/编辑字段。
但是由于某种原因,我无法更新数据库中的字段。

[HttpPost]
[ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(EditProfileViewModel model)
{
    if (ModelState.IsValid)
    {
        // Get the current application user
        var user = User.Identity.GetApplicationUser();

        // Update the details
        user.Name = new Name { First = model.FirstName, Last = model.LastName, Nickname = model.NickName };
        user.Birthday = model.Birthdate;

        // This is the part that doesn't work
        var result = await UserManager.UpdateAsync(user);

        // However, it always succeeds inspite of not updating the database
        if (!result.Succeeded)
        {
            AddErrors(result);
        }
    }

    return RedirectToAction("Manage");
}

我的问题类似于MVC5 ApplicationUser custom properties,但这似乎使用的是旧版本的 Identity,因为 IdentityManager 类似乎不存在。

谁能指导我如何更新数据库中的User 信息?

更新: 如果我在注册表单中包含所有字段,则所有值都存储在数据库中Users 表的新记录中的相应字段中。

我不知道要更改现有用户的字段(users 表中的行)。 UserManager.UpdateAsync(user) 不起作用。

另请注意,我的问题比 EntityFramework 更面向身份

【问题讨论】:

  • 在更改 ApplicationUser 后,您是否检查过执行更新数据库? “名称”也是一个类引用,它应该在 OnModelCreating 中进行适当的序列化或映射。
  • 不,没问题,数据库结构和ApplicationUser一样。 name 字段是数据库中的一列(如 Name_First、Name_Last 和 Name_NickName)。我的问题是当我调用UserManager.UpdateAsync(user) 时文件数据库没有更新为新值。我只想知道我应该如何更新 ApplicationUser(用户表)
  • ApplicationUser 和 OnModelCreating 代码 sn-ps 有助于解决此问题。从您的评论来看,这似乎是 Name 属性及其部分的映射问题。
  • @jd4u 更新 ApplicationUser(Users 表) 我指的是表中的值,而不是表的结构。映射是正确的,并且正在使用注册表单。信息无法更新。

标签: asp.net-mvc asp.net-mvc-5 asp.net-identity


【解决方案1】:

好的...我花了几个小时试图弄清楚为什么 userManager.updateAsync 不会保留我们编辑的用户数据...直到我得出以下结论:

混淆源于我们在一行中创建UserManager,如下所示:

var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyDbContext()));

...然后我们使用manager.UpdateAsync( user );,但这会更新上下文中的用户,然后我们需要将更改保存到身份的dbcontext。所以,问题是如何以最简单的方式获取 Identity DBcontext。

为了解决这个问题,我们不应该在一行中创建UserManager ...我是这样做的:

var store = new UserStore<ApplicationUser>(new MyDbContext());
var manager = new UserManager(store);

然后在通过调用更新用户之后

manager.UpdateAsync(user);

然后你去上下文

var ctx = store.context;

然后

ctx.saveChanges();

哇哇哇...坚持:)

希望这能帮助那些拉了几个小时头发的人:P

【讨论】:

  • 最后两步的捷径:store.context.saveChanges();
  • 最后 .. 对于那些需要全面实施的人来说,这个链接非常好weblogs.asp.net/imranbaloch/archive/2013/12/12/…
  • 我认为调用 updateAsync 然后两行保存上下文更改是错误的。这不会出现竞争条件吗?
  • 你的意思是我们应该使用await
  • 真的有必要做ctx.saveChanges();在 UpdateAsync() 之后?我不这么认为。并且不要忘记将“new MyDbContext()”关闭到 using 块。
【解决方案2】:

如果您为 ApplicationUser 或 IdentityUser 保留任何字段null,更新将成功返回,但不会将数据保存在数据库中。

示例解决方案:

ApplicationUser model = UserManager.FindById(User.Identity.GetUserId())

添加新更新的字段:

model.Email = AppUserViewModel.Email;
model.FName = AppUserViewModel.FName;
model.LName = AppUserViewModel.LName;
model.DOB = AppUserViewModel.DOB;
model.Gender = AppUserViewModel.Gender;

调用 UpdateAsync

IdentityResult result = await UserManager.UpdateAsync(model);

我已经对此进行了测试,并且可以正常工作。

【讨论】:

  • 我最终得到了类似的选项。刚刚使用 Automapper 进行映射模型。它看起来像这样:Mapper.Map(AppUserViewModel, Model);
  • 意思是我不能让其中一个字段保持为空
  • 我觉得应该是IdentityResult result = await UserManager.UpdateAsync(model);small m for model
【解决方案3】:

OWIN 上下文允许您获取 db 上下文。到目前为止,我似乎工作得很好,毕竟,我从 ApplciationUserManager 类中得到了这个想法,它做同样的事情。

    internal void UpdateEmail(HttpContext context, string userName, string email)
    {
        var manager = context.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var user = manager.FindByName(userName);
        user.Email = email;
        user.EmailConfirmed = false;
        manager.Update(user);
        context.GetOwinContext().Get<ApplicationDbContext>().SaveChanges();
    }

【讨论】:

  • 我认为不再需要最后一行了(这个问题在 Identity 是新的时候被问到)。我刚刚检查了一个最近项目的源代码控制,并注意到我只做了await UserManager.UpdateAsync(user) 并且更改仍然存在。你能确认一下吗?
  • 我可以确认,对于这个例子,最后一行是最明确地需要将更改持久化到数据库中。这是使用可用于网络表单应用程序的最新稳定版 Identity 2。也许 Async 方法的操作方式不同?
  • 我将 Owin 与 IOC 一起使用(从非异步辅助函数内部调用 Update()),这是唯一适用于标准 Owin 上下文的解决方案。为拯救我的一天和 +1 干杯
【解决方案4】:

UserManager 不起作用,正如@Kevin Junghans 所写,

UpdateAsync 只是将更新提交到上下文,您仍然需要保存上下文以将其提交到数据库

这是我在 web 表单 projetc 中使用的快速解决方案(在 ASP.net identity v2 中的新功能之前)。

class AspNetUser :IdentityUser

从 SqlServerMembership aspnet_Users 迁移而来。并且定义了上下文:

public partial class MyContext : IdentityDbContext<AspNetUser>

对于反射和同步代码,我深表歉意——如果您将其放在异步方法中,请使用 await 进行异步调用并删除 Tasks 和 Wait()。 arg,props,包含要更新的属性的名称。

 public static void UpdateAspNetUser(AspNetUser user, string[] props)
 {
     MyContext context = new MyContext();
     UserStore<AspNetUser> store = new UserStore<AspNetUser>(context);
     Task<AspNetUser> cUser = store.FindByIdAsync(user.Id); 
     cUser.Wait();
     AspNetUser oldUser = cUser.Result;

    foreach (var prop in props)
    {
        PropertyInfo pi = typeof(AspNetUser).GetProperty(prop);
        var val = pi.GetValue(user);
        pi.SetValue(oldUser, val);
    }

    Task task = store.UpdateAsync(oldUser);
    task.Wait();

    context.SaveChanges();
 }

【讨论】:

    【解决方案5】:

    在开发使用 ASP.NET 标识的 SimpleSecurity 版本时,我在使用 UpdateAsync 时也遇到了问题。例如,我添加了一项功能来进行密码重置,该功能需要将密码重置令牌添加到用户信息中。起初我尝试使用 UpdateAsync,它得到了和你一样的结果。我最终将用户实体包装在存储库模式中并让它工作。你可以看看SimpleSecurity project for an example。在更多地使用 ASP.NET Identity 之后(文档仍然不存在)我认为 UpdateAsync 只是将更新提交到上下文,您仍然需要保存上下文以将其提交到数据库。

    【讨论】:

    • 是的`UpdateAsync 只是将更新提交到上下文,[...] 保存上下文以将其提交到数据库'
    【解决方案6】:

    我以相同的方式尝试了该功能,当我调用UserManager.Updateasync 方法时它成功但数据库中没有更新。花了一些时间后,我找到了另一个解决方案来更新aspnetusers 表中的数据,如下所示:

    1) 你需要像这样创建UserDbContext 类继承自IdentityDbContext 类:

    public class UserDbContext:IdentityDbContext<UserInfo>
    {
        public UserDbContext():
            base("DefaultConnection")
        {
            this.Configuration.ProxyCreationEnabled = false;
        }
    }
    

    2) 然后在帐户控制器中更新用户信息,如下所示:

    UserDbContext userDbContext = new UserDbContext();
    userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified;
    await userDbContext.SaveChangesAsync();
    

    user 是您更新后的实体。

    希望这会对你有所帮助。

    【讨论】:

      【解决方案7】:

      太棒了!!!

      IdentityResult result = await UserManager.UpdateAsync(user);
      

      【讨论】:

      • 我知道它现在有效,但当时它不起作用:p 身份框架当时相对较新
      • 如果可行,我使用的是 VS 2013 MVC 5 - EntityFramework,版本 = 6。
      • MVC 5 使用了 Identity 2.0 对吗?正如我所说,这个问题已经很老了。
      • 我不知道我是不是在做这个坏事,还是应该改变它?
      • 版本 system.Web.Mvc: 5.2.3.0
      【解决方案8】:

      根据您的问题并在评论中注明。

      谁能指导我如何更新数据库中的用户信息?

      是的,代码对于将任何ApplicationUser 更新到数据库都是正确的。

      IdentityResult result = await UserManager.UpdateAsync(user);

      • 检查所有字段所需值的约束
      • 检查 UserManager 是使用 ApplicationUser 创建的。

      UserManager&lt;ApplicationUser&gt; UserManager = new UserManager&lt;ApplicationUser&gt;(new UserStore&lt;ApplicationUser&gt;(new ApplicationDbContext()));

      【讨论】:

      • 在检查ModelState.IsValid时没有检查约束吗?
      • ModelState 检查视图模型。您正在使用 GetApplicationUser() 从 Db 获取 ApplicationUser。
      • 此外,UpdateManager.Update 只是在默认实现中对用户名执行一次验证,然后再向 UserStore 发送更新调用。尝试直接使用 UserStore 进行调试。
      • @anyone,在将任何答案标记为无用时,请阅读所有内容并记住一点上下文。这个答案在上下文中是正确的。此外,这里选择的答案不是解决方案,它的替代方法忽略了身份框架的核心框架并直接使用数据库。
      【解决方案9】:

      这对我有用。我正在使用 Identity 2.0,看起来 GetApplicationUser 已经不存在了。

              var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
              if (!string.IsNullOrEmpty(form["FirstName"]))
              {
                  user.FirstName = form["FirstName"];
              }
              if (!string.IsNullOrEmpty(form["LastName"]))
              {
                  user.LastName = form["LastName"];
              }
              IdentityResult result = await UserManager.UpdateAsync(user);
      

      【讨论】:

      • GetApplicationUser() 是自定义扩展方法
      【解决方案10】:

      我正在使用新的 EF 和 Identity Core,但我遇到了同样的问题,另外我遇到了这个错误:

      无法跟踪实体类型的实例,因为另一个实例 已在跟踪具有相同密钥的此类类型。

      使用新的 DI 模型,我将构造函数的 Controller 上下文添加到 DB。

      我试图查看与_conext.ChangeTracker.Entries() 的冲突,并将AsNoTracking() 添加到我的通话中,但没有成功。

      我只需要更改我的对象的状态(在本例中为身份)

      _context.Entry(user).State = EntityState.Modified;
      var result = await _userManager.UpdateAsync(user);
      

      并且在没有创建另一个商店或对象和映射的情况下工作。

      我希望别人对我的两分钱有用。

      【讨论】:

        【解决方案11】:

        将以下代码添加到静态构造函数下的 Startup.Auth.cs 文件中:

                UserManagerFactory = () => new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
        
                OAuthOptions = new OAuthAuthorizationServerOptions
                {
                    TokenEndpointPath = new PathString("/Token"),
                    Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
                    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                    AllowInsecureHttp = true
                };
        

        UserManagerFactory 设置代码行用于将自定义 DataContext 与 UserManager 相关联。完成此操作后,您可以在 ApiController 中获取 UserManager 的实例,并且 UserManager.UpdateAsync(user) 方法将起作用,因为它使用您的 DataContext 来保存您添加到自定义应用程序用户的额外属性。

        【讨论】:

        • 您的代码包含很多与问题无关的内容。我建议你把它清理干净。
        【解决方案12】:

        我正在使用.Net Core 3.1 或更高版本。请按照解决方案:

          public class UpdateAssignUserRole
            {
                public string username { get; set; }
                public string rolename { get; set; }
                public bool IsEdit { get; set; }
        
            }
        
         private async Task UpdateSeedUsers(UserManager<IdentityUser> userManager, UpdateAssignUserRole updateassignUsername)
                {
                    IList<Users> Users = await FindByUserName(updateassignUsername.username);
        
                    if (await userManager.FindByNameAsync(updateassignUsername.username) != null)
                    {
                        var user = new IdentityUser
                        {
                            UserName = updateassignUsername.username,
                            Email = Users[0].Email,
         
                        };
                        var result = await userManager.FindByNameAsync(updateassignUsername.username);
                        if (result != null)
                        {
                            IdentityResult deletionResult = await userManager.RemoveFromRolesAsync(result, await userManager.GetRolesAsync(result));
                            if (deletionResult != null)
                            {
                                await userManager.AddToRoleAsync(result, updateassignUsername.rolename);
                            }
                        }
                    }
        
                }
        

        【讨论】:

        • 我认为您错过了 OP 的观点 - 他们在谈论用户的自定义字段/属性,您的示例是在删除/播种用户时从用户分配/删除角色,我不太了解相关性或这实际上如何解决 OP 的问题
        猜你喜欢
        • 1970-01-01
        • 2014-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多