ASP.NET身份DbContext混淆

一个默认的MVC 5应用程序在IdentityModels.cs中附带了这段代码 – 这段代码用于默认模板的所有ASP.NET标识操作:

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

如果我使用entity framework使用视图来支撑一个新的控制器,并在对话框中创build一个“新的数据上下文…”,我得到这个为我生成的:

 using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Web; namespace WebApplication1.Models { public class AllTheOtherStuffDbContext : DbContext { // You can add custom code to this file. Changes will not be overwritten. // // If you want Entity Framework to drop and regenerate your database // automatically whenever you change your model schema, please use data migrations. // For more information refer to the documentation: // http://msdn.microsoft.com/en-us/data/jj591621.aspx public AllTheOtherStuffDbContext() : base("name=AllTheOtherStuffDbContext") { } public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; } } } 

如果我脚手架另一个控制器+视图使用EF,例如说一个动物模型,这个新的行会自动生成在public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; } public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; } public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; } – 像这样:

 using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Web; namespace WebApplication1.Models { public class AllTheOtherStuffDbContext : DbContext { // You can add custom code to this file. Changes will not be overwritten. // // If you want Entity Framework to drop and regenerate your database // automatically whenever you change your model schema, please use data migrations. // For more information refer to the documentation: // http://msdn.microsoft.com/en-us/data/jj591621.aspx public AllTheOtherStuffDbContext() : base("name=AllTheOtherStuffDbContext") { } public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; } public System.Data.Entity.DbSet<WebApplication1.Models.Animal> Animals { get; set; } } } 

ApplicationDbContext (对于所有的ASP.NET身份的东西)inheritanceIdentityDbContext继而从DbContextinheritance。 AllOtherStuffDbContext (对于我自己的东西)从DbContextinheritance。

所以我的问题是:

这两个( ApplicationDbContextAllOtherStuffDbContext )哪一个应该用于我所有的其他自己的模型? 或者我应该只使用默认的自动生成的ApplicationDbContext因为它不应该是一个使用它的问题,因为它从基类DbContext ,或将有一些开销? 你应该只在应用程序中为你的所有模型使用一个DbContext对象(我读过这个地方),所以我甚至不应该考虑在一个应用程序中同时使用ApplicationDbContextAllOtherStuffDbContext ? 或者什么是ASP.NET身份的MVC 5中的最佳做法?

我将使用从IdentityDbContextinheritance的单个Context类。 通过这种方式,您可以让上下文了解您的类与IdentityDserContext和IdentityDbContext的angular色之间的任何关系。 IdentityDbContext中的开销很小,它基本上是一个具有两个DbSets的常规DbContext。 一个为用户,另一个为angular色。

在IdentityDbContext周围肯定有很多混乱,围绕SO进行快速search,您会发现很多有关此主题的问题:
“ 为什么Asp.Net IdentityDbContext是一个黑盒?
如何在使用Visual Studio 2013 AspNet Identity时更改表名?
合并MyDbContext与IdentityDbContext “

为了回答所有这些问题,我们只需要解决,IdentityDbContext只是一个从DbContextinheritance而来的类。
我们来看看IdentityDbContext的来源 :

 /// <summary> /// Base class for the Entity Framework database context used for identity. /// </summary> /// <typeparam name="TUser">The type of user objects.</typeparam> /// <typeparam name="TRole">The type of role objects.</typeparam> /// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam> /// <typeparam name="TUserClaim">The type of the user claim object.</typeparam> /// <typeparam name="TUserRole">The type of the user role object.</typeparam> /// <typeparam name="TUserLogin">The type of the user login object.</typeparam> /// <typeparam name="TRoleClaim">The type of the role claim object.</typeparam> /// <typeparam name="TUserToken">The type of the user token object.</typeparam> public abstract class IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : DbContext where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin> where TRole : IdentityRole<TKey, TUserRole, TRoleClaim> where TKey : IEquatable<TKey> where TUserClaim : IdentityUserClaim<TKey> where TUserRole : IdentityUserRole<TKey> where TUserLogin : IdentityUserLogin<TKey> where TRoleClaim : IdentityRoleClaim<TKey> where TUserToken : IdentityUserToken<TKey> { /// <summary> /// Initializes a new instance of <see cref="IdentityDbContext"/>. /// </summary> /// <param name="options">The options to be used by a <see cref="DbContext"/>.</param> public IdentityDbContext(DbContextOptions options) : base(options) { } /// <summary> /// Initializes a new instance of the <see cref="IdentityDbContext" /> class. /// </summary> protected IdentityDbContext() { } /// <summary> /// Gets or sets the <see cref="DbSet{TEntity}"/> of Users. /// </summary> public DbSet<TUser> Users { get; set; } /// <summary> /// Gets or sets the <see cref="DbSet{TEntity}"/> of User claims. /// </summary> public DbSet<TUserClaim> UserClaims { get; set; } /// <summary> /// Gets or sets the <see cref="DbSet{TEntity}"/> of User logins. /// </summary> public DbSet<TUserLogin> UserLogins { get; set; } /// <summary> /// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles. /// </summary> public DbSet<TUserRole> UserRoles { get; set; } /// <summary> /// Gets or sets the <see cref="DbSet{TEntity}"/> of User tokens. /// </summary> public DbSet<TUserToken> UserTokens { get; set; } /// <summary> /// Gets or sets the <see cref="DbSet{TEntity}"/> of roles. /// </summary> public DbSet<TRole> Roles { get; set; } /// <summary> /// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims. /// </summary> public DbSet<TRoleClaim> RoleClaims { get; set; } /// <summary> /// Configures the schema needed for the identity framework. /// </summary> /// <param name="builder"> /// The builder being used to construct the model for this context. /// </param> protected override void OnModelCreating(ModelBuilder builder) { builder.Entity<TUser>(b => { b.HasKey(u => u.Id); b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique(); b.HasIndex(u => u.NormalizedEmail).HasName("EmailIndex"); b.ToTable("AspNetUsers"); b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken(); b.Property(u => u.UserName).HasMaxLength(256); b.Property(u => u.NormalizedUserName).HasMaxLength(256); b.Property(u => u.Email).HasMaxLength(256); b.Property(u => u.NormalizedEmail).HasMaxLength(256); b.HasMany(u => u.Claims).WithOne().HasForeignKey(uc => uc.UserId).IsRequired(); b.HasMany(u => u.Logins).WithOne().HasForeignKey(ul => ul.UserId).IsRequired(); b.HasMany(u => u.Roles).WithOne().HasForeignKey(ur => ur.UserId).IsRequired(); }); builder.Entity<TRole>(b => { b.HasKey(r => r.Id); b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex"); b.ToTable("AspNetRoles"); b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken(); b.Property(u => u.Name).HasMaxLength(256); b.Property(u => u.NormalizedName).HasMaxLength(256); b.HasMany(r => r.Users).WithOne().HasForeignKey(ur => ur.RoleId).IsRequired(); b.HasMany(r => r.Claims).WithOne().HasForeignKey(rc => rc.RoleId).IsRequired(); }); builder.Entity<TUserClaim>(b => { b.HasKey(uc => uc.Id); b.ToTable("AspNetUserClaims"); }); builder.Entity<TRoleClaim>(b => { b.HasKey(rc => rc.Id); b.ToTable("AspNetRoleClaims"); }); builder.Entity<TUserRole>(b => { b.HasKey(r => new { r.UserId, r.RoleId }); b.ToTable("AspNetUserRoles"); }); builder.Entity<TUserLogin>(b => { b.HasKey(l => new { l.LoginProvider, l.ProviderKey }); b.ToTable("AspNetUserLogins"); }); builder.Entity<TUserToken>(b => { b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name }); b.ToTable("AspNetUserTokens"); }); } } 

如果我们想要将IdentityDbContext与我们的DbContext合并,基于源代码,我们有两个select:

第一个选项:
创build一个从IdentityDbContextinheritance的DbContext,并有权访问这些类。

  public class ApplicationDbContext : IdentityDbContext { public ApplicationDbContext() : base("DefaultConnection") { } static ApplicationDbContext() { Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer()); } public static ApplicationDbContext Create() { return new ApplicationDbContext(); } // Add additional items here as needed } 

额外的笔记:

1)我们还可以使用以下解决scheme更改asp.net标识默认表名:

  public class ApplicationDbContext : IdentityDbContext { public ApplicationDbContext(): base("DefaultConnection") { } protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<IdentityUser>().ToTable("user"); modelBuilder.Entity<ApplicationUser>().ToTable("user"); modelBuilder.Entity<IdentityRole>().ToTable("role"); modelBuilder.Entity<IdentityUserRole>().ToTable("userrole"); modelBuilder.Entity<IdentityUserClaim>().ToTable("userclaim"); modelBuilder.Entity<IdentityUserLogin>().ToTable("userlogin"); } } 

2)此外,我们可以扩展每个类,并将任何属性添加到类,如“IdentityUser”,“IdentityRole”,…

  public class ApplicationRole : IdentityRole<string, ApplicationUserRole> { public ApplicationRole() { this.Id = Guid.NewGuid().ToString(); } public ApplicationRole(string name) : this() { this.Name = name; } // Add any custom Role properties/code here } // Must be expressed in terms of our custom types: public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim> { public ApplicationDbContext() : base("DefaultConnection") { } static ApplicationDbContext() { Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer()); } public static ApplicationDbContext Create() { return new ApplicationDbContext(); } // Add additional items here as needed } 

为了节省时间,我们可以使用AspNet Identity 2.0 Extensible Project Template来扩展所有的类。

第二个选项:(不推荐)
如果我们自己编写所有的代码,我们实际上不必从IdentityDbContextinheritance。
所以基本上,我们可以从DbContextinheritance,并从IdentityDbContext源代码实现我们自定义版本的“OnModelCreating(ModelBuilder builder)”

如果深入了解IdentityDbContext的抽象,您会发现它看起来就像您的派生DbContext。 最简单的路线是Olav的答案,但是如果你想更多的控制什么是创build的,less一点依赖的身份包在这里看看我的问题和答案 。 如果您遵循链接,则有一个代码示例,但总括而言,您只需将所需的DbSets添加到您自己的DbContext子类中。

这是一个人们晚了,但下面是我的实施。 您还会注意到我删除了更改KEY缺省types的function:有关详细信息可以在以下文章中find:

  • 扩展身份模型并使用整数键而不是string
  • 更改ASP.NET身份用户的主键

笔记:
应该指出的是,你不能使用Guid's钥匙。 这是因为在引擎盖下他们是一个Struct ,因此,没有拆箱,这将允许他们从一个通用的<TKey>参数转换。

类看起来像:

 public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, string, CustomUserLogin, CustomUserRole, CustomUserClaim> { #region <Constructors> public ApplicationDbContext() : base(Settings.ConnectionString.Database.AdministrativeAccess) { } #endregion #region <Properties> //public DbSet<Case> Case { get; set; } #endregion #region <Methods> #region protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //modelBuilder.Configurations.Add(new ResourceConfiguration()); //modelBuilder.Configurations.Add(new OperationsToRolesConfiguration()); } #endregion #region public static ApplicationDbContext Create() { return new ApplicationDbContext(); } #endregion #endregion } public class ApplicationUser : IdentityUser<string, CustomUserLogin, CustomUserRole, CustomUserClaim> { #region <Constructors> public ApplicationUser() { Init(); } #endregion #region <Properties> [Required] [StringLength(250)] public string FirstName { get; set; } [Required] [StringLength(250)] public string LastName { get; set; } #endregion #region <Methods> #region private private void Init() { Id = Guid.Empty.ToString(); } #endregion #region public public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> 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; } #endregion #endregion } public class CustomUserStore : UserStore<ApplicationUser, CustomRole, string, CustomUserLogin, CustomUserRole, CustomUserClaim> { #region <Constructors> public CustomUserStore(ApplicationDbContext context) : base(context) { } #endregion } public class CustomUserRole : IdentityUserRole<string> { } public class CustomUserLogin : IdentityUserLogin<string> { } public class CustomUserClaim : IdentityUserClaim<string> { } public class CustomRoleStore : RoleStore<CustomRole, string, CustomUserRole> { #region <Constructors> public CustomRoleStore(ApplicationDbContext context) : base(context) { } #endregion } public class CustomRole : IdentityRole<string, CustomUserRole> { #region <Constructors> public CustomRole() { } public CustomRole(string name) { Name = name; } #endregion }