Обновление пользовательских данных - Идентификация ASP.NET

Я добавил пользовательские поля в класс 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 в базе данных?

UPDATE: Если я включаю все поля в регистрационную форму, все значения хранятся в соответствующем поле в новой записи таблицы Users из базы данных.

Я не знаю, чтобы вносить изменения в поля существующего пользователя (строка в таблице Users). UserManager.UpdateAsync(user) не работает.

Также обратите внимание, что моя проблема больше ориентирована на идентичность, чем EntityFramework

Ответ 1

ОК... Я потратил часы, пытаясь понять, почему userManager.updateAsync не будет сохраняться в пользовательских данных, которые мы редактируем... до тех пор, пока я не получу следующий вывод:

Путаница возникает из-за того, что мы создаем UserManager в одной строке следующим образом:

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

... тогда мы используем manager.UpdateAsync( user );, но это будет обновлять пользователя в контексте, а затем нам нужно будет сохранить изменения в dbcontext Identity. Итак, вопрос заключается в том, как проще всего получить контекст DB-кода Identity.

Чтобы решить эту проблему, мы не должны создавать UserManager в одной строке... и вот как я это делаю:

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

затем после обновления пользователя, вызвав

manager.UpdateAsync(user);

то вы переходите в контекст

var ctx = store.context;

затем

ctx.saveChanges();

wahooooooo... сохраняется:)

Надеюсь, это поможет кому-то, кто потянул свои волосы на несколько часов: P

Ответ 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);

Я тестировал это, и он работает.

Ответ 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();
    }

Ответ 4

UserManager не работал, и как писал @Kevin Junghans,

UpdateAsync просто передает обновление в контекст, вам все равно нужно сохранить контекст для его фиксации в базе данных

Вот быстрое решение (перед новыми функциями в ASP.net-идентификаторе v2), который я использовал в веб-формах projetc.

class AspNetUser :IdentityUser

Был перенесен из SqlServerMembership aspnet_Users. И контекст определяется:

public partial class MyContext : IdentityDbContext<AspNetUser>

Извиняюсь за отраженный и синхронный код - если вы поместите это в метод async, используйте await для асинхронных вызовов и удалите Tasks and Wait() s. Аргу, реквизит, содержит имена свойств для обновления.

 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

У меня также возникли проблемы с использованием UpdateAsync при разработке версии SimpleSecurity, которая использует идентификатор ASP.NET. Например, я добавил функцию, чтобы сделать пароль reset, который должен был добавить маркер пароля reset к пользовательской информации. Сначала я попытался использовать UpdateAsync и получил те же результаты, что и вы. Я закончил обертку пользовательского объекта в шаблоне репозитория и заставил его работать. Вы можете посмотреть проект SimpleSecurity для примера. После работы с ASP.NET Identity больше (документация по-прежнему отсутствует) Я думаю, что 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

Основываясь на вашем вопросе, а также отмечен в комментарии.

Может ли кто-нибудь помочь мне обновить информацию о пользователе в базе данных?

Да, код верен для обновления любого ApplicationUser в базе данных.

IdentityResult result = await UserManager.UpdateAsync(user);

  • Проверить ограничения для всех требуемых значений поля
  • Проверка UserManager создается с помощью ApplicationUser.

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

Ответ 8

Отлично!!!

IdentityResult result = await UserManager.UpdateAsync(user);

Ответ 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);

Ответ 10

Я использую новый EF и Identity Core, и у меня такая же проблема, с добавлением, что у меня есть эта ошибка:

Экземпляр типа сущности не может быть отслежен, потому что другой экземпляр этого типа с тем же ключом уже отслеживается.

В новой модели DI я добавил конструктор Controller в контекст к базе данных.

Я попытался понять, в чем конфликт с _conext.ChangeTracker.Entries() и добавить AsNoTracking() к моим вызовам без успеха.

Мне нужно только изменить состояние моего объекта (в этом случае Identity)

_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. Как только вы это сделаете, вы можете получить экземпляр UserManager в вашем ApiController, а метод UserManager.UpdateAsync(user) будет работать, потому что он использует ваш DataContext для сохранения дополнительных свойств, которые вы добавили к своему пользовательскому пользователю приложения.