Расширение ролей идентичности ASP.NET: IdentityRole не является частью модели для текущего контекста
Я пытаюсь использовать новую идентификатор ASP.NET в моем приложении MVC5, в частности, я пытаюсь интегрировать идентификатор ASP.NET в существующую базу данных. Я уже прочитал вопросы/ответы по SO, относящиеся к DB First и ASP.NET Identity, и выполнив все рекомендации, которые я по-прежнему не могу добавить роли в свою базу данных, хотя у меня нет проблем с добавлением пользователей. Здесь мой код:
var context = new PayrollDBEntities();
var roleManager = new RoleManager<AspNetRole>(new RoleStore<AspNetRole>(context));
bool roleExists = roleManager.RoleExists(roleDto.Name);
if (roleExists){
return false;
}
var role = new AspNetRole(roleDto.Name){
Name = roleDto.Name,
};
IdentityResult result = roleManager.Create(role);//Getting exception here
В последней строке кода я получаю исключение типа 'System.InvalidOperationException': The entity type IdentityRole is not part of the model for the current context.
Вот мой контекст:
public partial class PayrollDBEntities : IdentityDbContext
{
public PayrollDBEntities()
: base("name=PayrollDBEntities")
{
}
public virtual DbSet<AspNetRole> AspNetRoles { get; set; }
public virtual DbSet<AspNetUserClaim> AspNetUserClaims { get; set; }
public virtual DbSet<AspNetUserLogin> AspNetUserLogins { get; set; }
public virtual DbSet<AspNetUser> AspNetUsers { get; set; }
......
}
Мои классы AspNetUser
и AspNetRole
выводятся из IdentityUser
и IdentityRole
соответственно, но я все еще получаю это исключение. Вот моя диаграмма базы данных:
![enter image description here]()
Любая помощь будет принята с благодарностью.
Ответы
Ответ 1
После нескольких дней попыток заставить это работать без сбоев, я пришел к выводу, что если вы сначала используете Database и хотите интегрировать ASP.NET Identity в свое приложение, безусловно, самое простое и чистое решение является создание собственного поставщика членства путем переопределения ASP.NET Identity. Это на самом деле довольно легко, до сих пор я реализовал UserStore
и RoleStore
по своему вкусу. Я добавил столбцы/отношения, специфичные для моего домена, в мою базу данных, и всякий раз, когда я создаю пользователя или роль, я забочусь о фиксации своей базы данных, добавляя необходимые отношения. Моя реализация UserStore
довольно похожа на это. Моя реализация RoleStore
выглядит примерно так:
public class ApplicationRoleStore : IRoleStore<ApplicationRoleDTO>
{
private PayrollDBEntities _context;
public ApplicationRoleStore() { }
public ApplicationRoleStore(PayrollDBEntities database)
{
_context = database;
}
public Task CreateAsync(ApplicationRoleDTO role)
{
if (role == null)
{
throw new ArgumentNullException("RoleIsRequired");
}
var roleEntity = ConvertApplicationRoleDTOToAspNetRole(role);
_context.AspNetRoles.Add(roleEntity);
return _context.SaveChangesAsync();
}
public Task DeleteAsync(ApplicationRoleDTO role)
{
var roleEntity = _context.AspNetRoles.FirstOrDefault(x => x.Id == role.Id);
if (roleEntity == null) throw new InvalidOperationException("No such role exists!");
_context.AspNetRoles.Remove(roleEntity);
return _context.SaveChangesAsync();
}
public Task<ApplicationRoleDTO> FindByIdAsync(string roleId)
{
var role = _context.AspNetRoles.FirstOrDefault(x => x.Id == roleId);
var result = role == null
? null
: ConvertAspNetRoleToApplicationRoleDTO(role);
return Task.FromResult(result);
}
public Task<ApplicationRoleDTO> FindByNameAsync(string roleName)
{
var role = _context.AspNetRoles.FirstOrDefault(x => x.Name == roleName);
var result = role == null
? null
: ConvertAspNetRoleToApplicationRoleDTO(role);
return Task.FromResult(result);
}
public Task UpdateAsync(ApplicationRoleDTO role)
{
return _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
private ApplicationRoleDTO ConvertAspNetRoleToApplicationRoleDTO(AspNetRole aspRole)
{
return new ApplicationRoleDTO{
Id = aspRole.Id,
EnterpriseId = aspRole.EnterpriseId,
Name = aspRole.Name
};
}
private AspNetRole ConvertApplicationRoleDTOToAspNetRole(ApplicationRoleDTO appRole)
{
return new AspNetRole{
Id = appRole.Id,
EnterpriseId = appRole.EnterpriseId,
Name = appRole.Name,
};
}
}
И мое приложение RoleDTO:
public class ApplicationRoleDTO : IRole
{
public ApplicationRoleDTO()
{
Id = Guid.NewGuid().ToString();
}
public ApplicationRoleDTO(string roleName)
: this()
{
Name = roleName;
}
public string Id { get; set; }
public string Name { get; set; }
public Guid EnterpriseId { get; set; }
}
Я также нашел эти 2 статьи довольно полезными:
Обзор пользовательских провайдеров хранения для удостоверения ASP.NET
Реализация пользовательского провайдера хранилища удостоверений MySQL ASP.NET
Ответ 2
При создании пользовательского хранилища вам необходимо указать, что вместо IdentityRole используется AspNetRole. Вы можете добиться этого, используя класс UserStore с 6 параметрами типа:
new UserStore<AspNetUser, AspNetRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>(new PayrollDBEntities());
Это также указывает на изменения в создании Менеджера пользователей. Ниже приведен упрощенный пример создания необходимых экземпляров:
public class AspNetUser : IdentityUser { /*customization*/ }
public class AspNetRole : IdentityRole { /*customization*/ }
public class PayrollDBEntities : IdentityDbContext //or : IdentityDbContext <AspNetUser, AspNetRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
}
public class Factory
{
public IdentityDbContext DbContext
{
get
{
return new PayrollDBEntities();
}
}
public UserStore<AspNetUser, AspNetRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim> UserStore
{
get
{
return new UserStore<AspNetUser, AspNetRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>(DbContext);
}
}
public UserManager<AspNetUser, string> UserManager
{
get
{
return new UserManager<AspNetUser, string>(UserStore);
}
}
public RoleStore<AspNetRole> RoleStore
{
get
{
return new RoleStore<AspNetRole>(DbContext);
}
}
public RoleManager<AspNetRole> RoleManager
{
get
{
return new RoleManager<AspNetRole>(RoleStore);
}
}
}
Ответ 3
Я объясню здесь с помощью примеров кода:).
Фокус в том, что они уже находятся в IdentityDbContext (AspNetRoles, AspNetUserClaims, AspNetUsers,....)
В IdentityModel вы увидите, что ApplicationUser пуст в верхней части. Если вы хотите настроить этих пользователей или роли, просто добавьте свойства здесь, а затем обновите свою базу данных с помощью консоли.
Пример моего контекста
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<Request> Requests { get; set; }
public DbSet<Reservation> Reservations { get; set; }
public DbSet<PriceType> PriceTypes { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Price> Prices { get; set; }
public DbSet<GuestbookPost> Posts { get; set; }
public DbSet<Count> Counts { get; set; }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<InvoiceLine> InvoiceLines { get; set; }
...
}
Таким образом, пользователь приложения не определен здесь, но я добавил к нему дополнительные свойства, например:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string GroupName { get; set; }
public string Email { get; set; }
[StringLength(15)]
public string Phone { get; set; }
public string Remark { get; set; }
public DateTime? BirthDate { get; set; }
public DateTime ValidFrom { get; set; }
public DateTime ValidUntil { get; set; }
public string Street { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public virtual ICollection<Request> Requests { get; set; }
}
Ответ 4
Я знаю, что это старый вопрос, но на случай, если кто-то еще с трудом добавляет роли/пользователей, когда они модифицируют идентификатор asp для использования числовых первичных ключей (int/long) вместо строки по умолчанию для ролей Identity, поэтому, если вы изменили IdentityUserRole в IdentityModels.cs на что-то вроде этого:
public class Role : IdentityRole<long, UserRole>
{
public Role() { }
public Role(string name) { Name = name; }
}
Вы должны использовать класс Role
вместо стандартного IdentityRole
при построении RoleManager, поэтому ваш код должен выглядеть примерно так:
public static void RegisterUserRoles()
{
ApplicationDbContext context = new ApplicationDbContext();
var RoleManager = new RoleManager<Role, long>(new RoleStore(context));
if (!RoleManager.RoleExists("Administrador"))
{
var adminRole = new Role {
Name = "Administrador",
};
RoleManager.Create(adminRole);
}
}
Итак, это должно заполнить вашу базу данных правильно, я думаю, что все опытные ASP-программисты уже это знают, но для других это может занять некоторое время, чтобы понять.
Ответ 5
Я решил по-другому. Сначала я разделился на два разных проекта и контекстов. Мой проект, который обрабатывает идентичность, имеет такой контекст:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IDisposable
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Это мой ApplicationUser:
public class ApplicationUser : IdentityUser
{
//Put here the extra properties that Identity does not handle
[Required]
[MaxLength(150)]
public string Nome { 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;
}
}
И мой ApplicationUserManager выглядит так:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
//Setting validator to user name
UserValidator = new UserValidator<ApplicationUser>(this)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
//Validation Logic and Password complexity
PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = false,
RequireUppercase = false,
};
//Lockout
UserLockoutEnabledByDefault = true;
DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
MaxFailedAccessAttemptsBeforeLockout = 5;
// Providers de Two Factor Autentication
RegisterTwoFactorProvider("Código via SMS", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Seu código de segurança é: {0}"
});
RegisterTwoFactorProvider("Código via E-mail", new EmailTokenProvider<ApplicationUser>
{
Subject = "Código de Segurança",
BodyFormat = "Seu código de segurança é: {0}"
});
//Email service
EmailService = new EmailService();
// Definindo a classe de serviço de SMS
SmsService = new SmsService();
var provider = new DpapiDataProtectionProvider("Braian");
var dataProtector = provider.Create("ASP.NET Identity");
UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtector);
}
}
Я надеюсь, что это кому-то поможет. Это решение было из этой статьи: Эдуардо Пирес - но это на португальском
Ответ 6
Я исправил эту проблему, изменив свойство webconfig DefaultConnection connectionString, чтобы он указывал на новую базу данных SQLServer