更新用户数据-ASP.NET身份


75

我向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自定义属性,但似乎使用了较旧的Identity版本,因为IdentityManager类似乎不存在。

有人可以指导我如何更新User数据库中的信息吗?

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

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

还要注意我的问题比EntityFramework更面向身份


更改ApplicationUser后,是否检查过执行Update-Database?同样,“名称”是类引用,应在OnModelCreating中适当地序列化或映射。
jd4u 2013年

没关系,数据库结构与相同ApplicationUser。名称字段是数据库中的一列(如Name_First,Name_Last和Name_NickName)。我的问题是在调用时文件数据库没有更新为新值UserManager.UpdateAsync(user)。我只想知道我应该如何更新ApplicationUser(用户表)
galdin 2013年

ApplicationUser和OnModelCreating代码段有助于解决此问题。从您的评论看来,这似乎是Name属性及其部分的映射问题。
jd4u 2013年

@ jd4u通过更新ApplicationUser(用户表),我的意思是表中的值而不是表的结构。映射是正确的,并且正在使用注册表。该信息无法更新。
galdin 2013年

Answers:


99

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

混淆是由于我们UserManager像这样在一行中创建了一个事实:

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

...然后我们使用,manager.UpdateAsync( user );但这将在上下文中更新用户,然后我们需要将更改保存到Identity的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();

wahooooooo ...坚持:)

希望这可以帮助拉了几个小时的头发的人:P


4
最后两步的快捷方式:store.context.saveChanges();
stackunderflow 2014年

3
终于..对于那些谁需要全面实施这个环节非常出色weblogs.asp.net/imranbaloch/archive/2013/12/12/...
stackunderflow

2
我认为调用updateAsync是错误的,然后两行保存上下文更改。那不代表比赛条件吗?
mac10688

1
您的意思是我们应该使用await
stackunderflow 2014年

1
真的有必要做ctx.saveChanges();吗?在UpdateAsync()之后?我不这么认为。并且不要忘记将“ new MyDbContext()”放到使用块中。
亚历山大

58

如果将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);
Oleksii Aza 2014年

意思是我不能让其中一个字段保持为空
galdin 2014年

我觉得应该是IdentityResult result = await UserManager.UpdateAsync(model);对模型小M
干扰机

12

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();
    }

3
我认为不再需要最后一行(当Identity是新的时,会问这个问题)。我只是检查了最近项目的源代码控制,发现我只是这样做了await UserManager.UpdateAsync(user),所以更改仍然存在。能否请你确认?
galdin 2015年

1
我可以确认,对于此示例,最肯定需要最后一行来将更改持久保存到数据库。这使用的是Webforms应用程序可用的Identity 2的最新稳定版本。也许异步方法的操作方式有所不同?
Atters 2015年

我将Owin与IOC结合使用(Update()从非异步帮助函数内部调用),这是唯一与标准Owin上下文一起使用的解决方案。为挽救我的生活和+1欢呼
编码

5

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()。args 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();
 }

3

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


是的,`UpdateAsync只是将更新提交到上下文,保存上下文以供其提交到数据库。”
subsci 2014年

3

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

1)您需要创建UserDbContextIdentityDbContext此类继承的类,如下所示:

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您更新后的实体在哪里。

希望这会帮助你。


2

优秀的!!!

IdentityResult result = await UserManager.UpdateAsync(user);

我知道现在可以正常工作了,尽管它当时还不可行:p Identity框架当时相对较新
galdin

如果有效,我正在使用VS 2013 MVC 5-EntityFramework,版本=6。–
Max

MVC 5用过Identity 2.0对吗?正如我所说,这个问题已经很老了。
galdin '16

我不知道我是否在使用这种邪恶的方法,还是应该改变它?
Max

版本system.Web.Mvc:5.2.3.0
马克斯

1

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

有人可以指导我如何更新数据库中的用户信息吗?

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

IdentityResult result = await UserManager.UpdateAsync(user);

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

UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));


检查时不检查约束ModelState.IsValid吗?
galdin 2013年

ModelState检查视图模型。您正在使用GetApplicationUser()从Db获取ApplicationUser。
jd4u 2013年

此外,在将更新调用发送到UserStore之前,UpdateManager.Update仅在默认实现中对用户名执行一次验证。尝试直接使用UserStore进行调试。
jd4u 2013年

2
@任何人,在将任何答案标记为无用时,请阅读所有内容并记住一些上下文。这个答案对上下文是正确的。而且,这里选择的答案不是解决方案,它的替代方法忽略了Identity Framework的核心框架,而是直接与数据库一起使用。
jd4u 2014年

0

这对我有用。我正在使用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()是自定义扩展方法
galdin

0

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

无法跟踪实体类型的实例,因为已经跟踪了具有相同键的该类型的另一个实例。

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

我试图查看与电话发生了什么冲突,_conext.ChangeTracker.Entries()并增加AsNoTracking()了通话失败。

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

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

并且无需创建另一个商店或对象以及映射即可工作。

我希望别人能帮到我两美分。


0

我使用的是.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);
                    }
                }
            }

        }

-1

将以下代码添加到静态构造函数下的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来保存已添加到自定义应用程序用户的其他属性。


您的代码包含许多与问题无关的内容。我建议你清理一下。
Zero3 '04 -4-4
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.