ASP。NET Identity DbContext混淆

默认的MVC 5应用程序带有IdentityModels.cs中的这段代码-这段代码用于所有的ASP。NET默认模板的标识操作:

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

如果我使用实体框架的视图脚手架一个新的控制器,并在对话框中创建一个“新数据上下文…”,我得到这个为我生成:

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; }下自动生成-就像这样:

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. b0。NET Identity的东西)继承自IdentityDbContext,而IdentityDbContext又继承自DbContextAllOtherStuffDbContext (for my own stuff)继承自DbContext

所以我的问题是:

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

149034 次浏览
我将使用从IdentityDbContext继承的单个Context类。 通过这种方式,您可以让上下文知道您的类与IdentityUser和IdentityDbContext的Roles之间的任何关系。 在IdentityDbContext中有很少的开销,它基本上是一个带有两个dbset的常规DbContext。一个用于用户,一个用于角色

如果您深入研究IdentityDbContext的抽象,您会发现它看起来就像派生的DbContext。最简单的方法是Olav的答案,但如果你想更多地控制所创建的内容,并减少对Identity包看看我的问题和答案在这里的依赖。这里有一个代码示例,但总的来说,你只需要将所需的dbset添加到你自己的DbContext子类中。

这是一个较晚的条目,但下面是我的实现。你还会注意到我增加了更改KEYs默认类型的能力:关于它的详细信息可以在以下文章中找到:

< p > 注:
应该注意的是,你不能使用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
}
关于IdentityDbContext有很多困惑,在Stackoverflow中快速搜索,你会发现这些问题 " 为什么Asp。Net Identity IdentityDbContext a Black-Box? < br > 如何在使用Visual Studio 2013 AspNet Identity时更改表名? < br > 合并MyDbContext和IdentityDbContext " < / p > 要回答所有这些问题,我们需要理解IdentityDbContext只是一个继承自DbContext的类 让我们来看看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");
});
}
}
< p > < br > 根据源代码,如果我们想合并IdentityDbContext与DbContext,我们有两个选项:

第一选择: < br > 创建一个继承自IdentityDbContext的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
}

< br > < br > < em >额外注:< / em >

1)我们也可以改变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可扩展项目模板扩展所有的类

第二个选择:< em >(不推荐)
如果我们自己写所有的代码,我们实际上不需要从IdentityDbContext继承。< br > 因此,基本上我们可以从DbContext继承,并从IdentityDbContext源代码

实现我们的定制版本的“OnModelCreating(ModelBuilder builder builder)”