web-dev-qa-db-fra.com

Mise à jour des données utilisateur - Identité ASP.NET

J'ai ajouté des champs personnalisés à la classe ApplicationUser
J'ai également créé un formulaire à travers lequel l'utilisateur peut entrer/éditer les champs.
Cependant, pour une raison quelconque, je ne suis pas en mesure de mettre à jour les champs de la base de données.

[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");
}

Mon problème est similaire à propriétés personnalisées de MVC5 ApplicationUser , mais cela semble utiliser une version plus ancienne d'Identity, car la classe IdentityManager ne semble pas exister.

Est-ce que quelqu'un peut me guider sur la façon de mettre à jour User info dans la base de données?

UPDATE: Si j'inclus tous les champs du formulaire de registre, toutes les valeurs sont stockées dans le champ approprié dans un nouvel enregistrement de la table Users de la base de données.

Je ne sais pas comment modifier les champs d'un utilisateur existant (ligne de la table users.) UserManager.UpdateAsync(user) ne fonctionne pas.

Notez également que mon problème est davantage axé sur l'identité que sur EntityFramework

68
gldraphael

OK ... J'ai passé des heures à essayer de comprendre pourquoi userManager.updateAsync Ne conservait pas les données utilisateur que nous modifions ... jusqu'à ce que je parvienne à la conclusion suivante:

La confusion provient du fait que nous créons le UserManager en une ligne comme ceci:

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

... alors nous utilisons manager.UpdateAsync( user ); mais cela mettra à jour l'utilisateur dans le contexte, et nous devrons alors enregistrer les modifications apportées au dbcontext de l'identité. La question est donc de savoir comment obtenir le Identity DBcontext de la manière la plus simple.

Pour résoudre ce problème, nous ne devrions pas créer le UserManager en une seule ligne ... et voici comment je le fais:

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

puis après avoir mis à jour l'utilisateur en appelant

manager.UpdateAsync(user);

alors vous allez au contexte

var ctx = store.context;

ensuite

ctx.saveChanges();

wahooooooo ... a persisté :)

J'espère que cela aidera quelqu'un qui s'est coupé les cheveux pendant quelques heures: P

95
stackunderflow

Si vous laissez des champs pour ApplicationUser OR IdentityUser null), la mise à jour sera considérée comme réussie mais ne sauvegardera pas les données dans la base de données.

Exemple de solution:

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

Ajoutez les champs nouvellement mis à jour:

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

Appelez UpdateAsync

IdentityResult result = await UserManager.UpdateAsync(model);

J'ai testé cela et ça marche.

54
JoshdeVries

Le contexte OWIN vous permet d’obtenir le contexte de la base de données. Cela semble bien fonctionner jusqu'à présent pour moi et, après tout, j'ai eu l'idée de la classe ApplciationUserManager qui fait la même chose.

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

Le UserManager ne fonctionnait pas et @Kevin Junghans a écrit:

UpdateAsync valide simplement la mise à jour dans le contexte, vous devez toujours enregistrer le contexte pour qu'il puisse être validé dans la base de données.

Voici une solution rapide (avant les nouvelles fonctionnalités dans ASP.net identity v2) que j’ai utilisée dans un projet de formulaires Web. le

class AspNetUser :IdentityUser

A été migré depuis SqlServerMembership aspnet_Users. Et le contexte est défini:

public partial class MyContext : IdentityDbContext<AspNetUser>

Je m'excuse pour la réflexion et le code synchrone - si vous mettez cela dans une méthode async, utilisez await pour les appels asynchrones et supprimez les tâches et Wait (). L'argument, props, contient les noms des propriétés à mettre à jour.

 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
subsci

J'ai également eu des problèmes d'utilisation de UpdateAsync lors du développement d'une version de SimpleSecurity utilisant l'identité ASP.NET. Par exemple, j'ai ajouté une fonctionnalité permettant de réinitialiser un mot de passe, ce qui nécessitait d'ajouter un jeton de réinitialisation de mot de passe aux informations de l'utilisateur. Au début, j'ai essayé d'utiliser UpdateAsync et les résultats sont identiques à ceux que vous avez obtenus. J'ai fini par envelopper l'entité utilisateur dans un modèle de référentiel et le faire fonctionner. Vous pouvez regarder le projet SimpleSecurity pour un exemple . Après avoir travaillé davantage avec ASP.NET Identity (la documentation n’existe toujours pas), je pense que UpdateAsync ne fait que valider la mise à jour du contexte, vous devez toujours enregistrer le contexte pour qu’il soit validé dans la base de données.

3
Kevin Junghans

J'ai essayé la fonctionnalité de la même manière et quand j'appelle UserManager.Updateasync méthode réussit mais il n'y a pas de mise à jour dans la base de données. Après avoir passé du temps, j'ai trouvé une autre solution pour mettre à jour les données dans la table aspnetusers suivante:

1) vous devez créer la classe UserDbContext héritant de la classe IdentityDbContext comme ceci:

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

2) puis dans Account controller, mettez à jour les informations utilisateur comme ceci:

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

user est votre entité mise à jour.

j'espère que cela vous aidera.

3
Ankit Sahrawat

Excellent!!!

IdentityResult result = await UserManager.UpdateAsync(user);
2
Max

Basé sur votre question et également noté dans le commentaire.

Quelqu'un peut-il me guider sur la façon de mettre à jour les informations utilisateur dans la base de données?

Oui, le code est correct pour la mise à jour de ApplicationUser dans la base de données.

IdentityResult result = await UserManager.UpdateAsync(user);

  • Vérifier les contraintes de toutes les valeurs requises du champ
  • La vérification de UserManager est créée à l'aide de ApplicationUser.

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

1
jd4u

J'utilise le nouveau noyau EF & Identity Core et j'ai le même problème, mais j'ai aussi cette erreur:

L'instance de type entité ne peut pas être suivie car une autre instance de ce type avec la même clé est déjà suivie.

Avec le nouveau modèle DI, j'ai ajouté le contrôleur du constructeur au contexte de la base de données.

J'ai essayé de voir quels sont les conflits avec _conext.ChangeTracker.Entries() et d'ajouter AsNoTracking() à mes appels sans succès.

Je n'ai besoin que de changer l'état de mon objet (dans ce cas, Identity)

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

Et travaillé sans créer un autre magasin ou objet et mappage.

J'espère que quelqu'un d'autre est utile mes deux cents.

0
Ivan Paniagua

Cela fonctionne pour moi. J'utilise Identity 2.0, il semblerait que GetApplicationUser ne soit plus là.

        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);
0
Yan