using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations.Schema;using System.Data.Common;using System.Data.Entity;using System.Data.Entity.Infrastructure;using System.Data.Entity.Infrastructure.Annotations;using System.Data.Entity.Validation;using System.Data.SqlClient;using System.Diagnostics.CodeAnalysis;using System.Globalization;using System.Linq;namespace Microsoft.AspNet.Identity.EntityFramework{ ////// Default db context that uses the default entity types /// public class IdentityDbContext : IdentityDbContext{ /// /// Default constructor which uses the DefaultConnection /// public IdentityDbContext() : this("DefaultConnection") { } ////// Constructor which takes the connection string to use /// /// public IdentityDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { } ////// Constructs a new context instance using the existing connection to connect to a database, and initializes it from /// the given model. The connection will not be disposed when the context is disposed if contextOwnsConnection is /// false. /// /// An existing connection to use for the new context. /// The model that will back this context. /// /// Constructs a new context instance using the existing connection to connect to a /// database, and initializes it from the given model. The connection will not be disposed when the context is /// disposed if contextOwnsConnection is false. /// public IdentityDbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection) : base(existingConnection, model, contextOwnsConnection) { } } ////// DbContext which uses a custom user entity with a string primary key /// ///public class IdentityDbContext : IdentityDbContext where TUser : IdentityUser { /// /// Default constructor which uses the DefaultConnection /// public IdentityDbContext() : this("DefaultConnection") { } ////// Constructor which takes the connection string to use /// /// public IdentityDbContext(string nameOrConnectionString) : this(nameOrConnectionString, true) { } ////// Constructor which takes the connection string to use /// /// /// Will throw an exception if the schema matches that of Identity 1.0.0 public IdentityDbContext(string nameOrConnectionString, bool throwIfV1Schema) : base(nameOrConnectionString) { if (throwIfV1Schema && IsIdentityV1Schema(this)) { throw new InvalidOperationException(IdentityResources.IdentityV1SchemaError); } } ////// Constructs a new context instance using the existing connection to connect to a database, and initializes it from /// the given model. The connection will not be disposed when the context is disposed if contextOwnsConnection is /// false. /// /// An existing connection to use for the new context. /// The model that will back this context. /// /// Constructs a new context instance using the existing connection to connect to a /// database, and initializes it from the given model. The connection will not be disposed when the context is /// disposed if contextOwnsConnection is false. /// public IdentityDbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection) : base(existingConnection, model, contextOwnsConnection) { } internal static bool IsIdentityV1Schema(DbContext db) { var originalConnection = db.Database.Connection as SqlConnection; // Give up and assume its ok if its not a sql connection if (originalConnection == null) { return false; } if (db.Database.Exists()) { using (var tempConnection = new SqlConnection(originalConnection.ConnectionString)) { tempConnection.Open(); return VerifyColumns(tempConnection, "AspNetUsers", "Id", "UserName", "PasswordHash", "SecurityStamp", "Discriminator") && VerifyColumns(tempConnection, "AspNetRoles", "Id", "Name") && VerifyColumns(tempConnection, "AspNetUserRoles", "UserId", "RoleId") && VerifyColumns(tempConnection, "AspNetUserClaims", "Id", "ClaimType", "ClaimValue", "User_Id") && VerifyColumns(tempConnection, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider"); } } return false; } [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities", Justification = "Reviewed")] internal static bool VerifyColumns(SqlConnection conn, string table, params string[] columns) { var tableColumns = new List(); using ( var command = new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@Table", conn)) { command.Parameters.Add(new SqlParameter("Table", table)); using (var reader = command.ExecuteReader()) { while (reader.Read()) { // Add all the columns from the table tableColumns.Add(reader.GetString(0)); } } } // Make sure that we find all the expected columns return columns.All(tableColumns.Contains); } } /// /// IdentityDbContext of IdentityUsers /// ////// /// /// /// /// public class IdentityDbContext : DbContext where TUser : IdentityUser where TRole : IdentityRole where TUserLogin : IdentityUserLogin where TUserRole : IdentityUserRole where TUserClaim : IdentityUserClaim { /// /// Default constructor which uses the "DefaultConnection" connectionString /// public IdentityDbContext() : this("DefaultConnection") { } ////// Constructor which takes the connection string to use /// /// public IdentityDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { } ////// Constructs a new context instance using the existing connection to connect to a database, and initializes it from /// the given model. The connection will not be disposed when the context is disposed if contextOwnsConnection is /// false. /// /// An existing connection to use for the new context. /// The model that will back this context. /// /// Constructs a new context instance using the existing connection to connect to a /// database, and initializes it from the given model. The connection will not be disposed when the context is /// disposed if contextOwnsConnection is false. /// public IdentityDbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection) : base(existingConnection, model, contextOwnsConnection) { } ////// EntitySet of Users /// public virtual IDbSetUsers { get; set; } /// /// EntitySet of Roles /// public virtual IDbSetRoles { get; set; } /// /// If true validates that emails are unique /// public bool RequireUniqueEmail { get; set; } ////// Maps table names, and sets up relationships between the various user entities /// /// protected override void OnModelCreating(DbModelBuilder modelBuilder) { if (modelBuilder == null) { throw new ArgumentNullException("modelBuilder"); } // Needed to ensure subclasses share the same table var user = modelBuilder.Entity() .ToTable("AspNetUsers"); user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId); user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId); user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId); user.Property(u => u.UserName) .IsRequired() .HasMaxLength(256) .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") { IsUnique = true })); // CONSIDER: u.Email is Required if set on options? user.Property(u => u.Email).HasMaxLength(256); modelBuilder.Entity () .HasKey(r => new { r.UserId, r.RoleId }) .ToTable("AspNetUserRoles"); modelBuilder.Entity () .HasKey(l => new { l.LoginProvider, l.ProviderKey, l.UserId }) .ToTable("AspNetUserLogins"); modelBuilder.Entity () .ToTable("AspNetUserClaims"); var role = modelBuilder.Entity () .ToTable("AspNetRoles"); role.Property(r => r.Name) .IsRequired() .HasMaxLength(256) .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true })); role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId); } /// /// Validates that UserNames are unique and case insenstive /// /// /// ///protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary
上面的代码出自:
https://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.EntityFramework/2.0.0-rtm-140221/Release/Default/Microsoft.AspNet.Identity.EntityFramework/Microsoft.AspNet.Identity.EntityFramework/IdentityDbContext.cs?ImageName=Microsoft.AspNet.Identity.EntityFramework
想查看Microsoft.AspNet.Identity.EntityFramework.dll中IdentityDbContext的源码,却发现Github上Identity的代码和实际调用的dll里面的结构不一致。
找到如上代码,留文备用。