Обновление пользовательских данных - Идентификация 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 для сохранения дополнительных свойств, которые вы добавили к своему пользовательскому пользователю приложения.