Подтвердить что ты не робот

Как обновить IdentityUser с помощью настраиваемых свойств с использованием MVC5 и структуры сущностей

Я использую встроенную систему идентификации для управления пользователями и хотел бы добавить несколько настроек в таблицу AspNetUsers. До сих пор решение каждой проблемы, с которой я столкнулся, вызывает еще одну проблему.

Если я вношу изменения в модель пользователя (например, добавив свойство zip-кода и соответствующее поле в таблице AspNetUsers), затем вызовите UserManager.UpdateAsync(пользователь), он будет успешным, но не обновит поле почтового индекса в базы данных.

Как минимум еще один вопрос SO попытался справиться с этим. Но предлагаемые исправления там нарушают другие вещи:

1) Создание другого экземпляра UserDbContext и попытка присоединения объекта пользователя заставляет сущность-структуру жаловаться на то, что "объект-объект не может ссылаться на несколько экземпляров IEntityChangeTracker"

2) Отключение создания прокси-сервера избавляет от проблемы, указанной в # 1, но приводит к тому, что dbcontext не загружает дочерние объекты (например, AspNetUserLogins, которые весьма важны).

Другим решением будет доступ к контексту, созданному в контроллере. Рассмотрите стандартные методы конструктора AccountController с новым веб-приложением ASP.NET с использованием шаблона MVC (версия 5):

 public AccountController()
            : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
        {
        }

        public AccountController(UserManager<ApplicationUser> userManager)
        {
            UserManager = userManager;
        }

Контекст БД приложения создается, но нет доступа к нему через UserManager (поскольку свойство "Store" для UserManager).

Это не похоже на ракетную науку, поэтому я предполагаю, что я делаю что-то в основном неправильное в отношении обработки/понимания жизненного цикла dbcontext.

Итак: как правильно получить/использовать dbcontext для сохранения и обновления AspNetUsers, связанных пользовательских свойств и сохранения дочерних объектов (например, AspNetUserLogins)?

РЕДАКТИРОВАТЬ -------

Еще одна вещь, которую я пробовал...

Я обновил конструктор AccountController по умолчанию:

    public AccountController(UserManager<ApplicationUser> userManager)
    {
       UserManager = userManager;
    }

:

    public AccountController(UserManager<ApplicationUser> userManager)
    {
        userDbContext= new UserDbContext();
        UserStore<ApplicationUser> store = new UserStore<ApplicationUser>();
        UserManager<ApplicationUser> manager = new UserManager<ApplicationUser>(store);

        manager.UserValidator = new CustomUserValidator<ApplicationUser>(UserManager);

       // UserManager = userManager;
        UserManager = manager;

    }

В попытке вставить dbcontext. Позже, в теле публичного метода async Task, я пытаюсь вызвать:

  var updated = await UserManager.UpdateAsync(user);

  if (updated.Succeeded)
  {
    userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified;
    await userDbContext.SaveChangesAsync();
  }

Однако попытка обновления состояния выдает исключение:

"Уже существует сгенерированный тип прокси для типа объекта-объекта" xyz.Models.ApplicationUser ". Это происходит, когда один и тот же тип слоя объектов отображается двумя или более разными моделями в AppDomain."

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

РЕДАКТИРОВАТЬ # 2 -----

Вот модель ApplicationUser:

using Microsoft.AspNet.Identity.EntityFramework;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using System.Data.Entity;

namespace xyz.App.Models
{
    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string ZipCode { get; set; }
        public string PasswordResetToken { get; set; }
        public System.DateTime? PasswordResetTokenExpiry { get; set; }

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }

        public ApplicationUser() { }

    }




    public class UserDbContext : IdentityDbContext<ApplicationUser>
    {
        public UserDbContext()
            : base("DefaultConnection")
        {

        }

    }
}

Заключительное редактирование ----------------------------

Хорошо, после некоторых комментариев и комментариев, я понял, что задал вопрос не так. Мой вопрос был действительно: как использовать сначала кодовые, а не первичные миграции баз данных. Исходя из школы Hibernate, я привык вручную сопоставлять объекты с таблицами через XML или аннотации в Java.

Итак, в skimming в этой статье я пропустил важные шаги по миграции. Извлеченный урок.

4b9b3361

Ответ 1

Итак, вы используете сначала базу данных, а не код-сначала. Моя рекомендация - сначала использовать код. Вместо этого я, как и вы, начал использовать базу данных. Если вы не используете код сначала, а затем удалите таблицу миграций в своей базе данных. В противном случае это вызовет проблемы.

Если это возможно, я рекомендую следовать этому руководству по первому коду, что очень помогло мне. Вы можете легко добавить пользовательские поля в свою личность и полностью интегрироваться с каркасом в случае аутентификации.

http://blogs.msdn.com/b/webdev/archive/2013/10/16/customizing-profile-information-in-asp-net-identity-in-vs-2013-templates.aspx

Ответ 2

Я столкнулся с той же проблемой. Простым способом преодоления этого было просто взять свойства, которые я хотел обновить из модели, и сохранить их обратно в объект, вытащенный из UserManager;

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(ApplicationUser model)
    {
        if (ModelState.IsValid)
        {
            ApplicationUser u = UserManager.FindById(model.Id);
            u.UserName = model.Email;
            u.Email = model.Email;
            u.StaffName = model.StaffName; // Extra Property
            UserManager.Update(u);
            return RedirectToAction("Index");
        }
        return View(model);
    }