• Microsoft.AspNet.Identity.EntityFramework/IdentityDbContext.cs


    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
    {
        /// <summary>
        ///     Default db context that uses the default entity types
        /// </summary>
        public class IdentityDbContext :
            IdentityDbContext<IdentityUser, IdentityRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
        {
            /// <summary>
            ///     Default constructor which uses the DefaultConnection
            /// </summary>
            public IdentityDbContext()
                : this("DefaultConnection")
            {
            }
    
            /// <summary>
            ///     Constructor which takes the connection string to use
            /// </summary>
            /// <param name="nameOrConnectionString"></param>
            public IdentityDbContext(string nameOrConnectionString)
                : base(nameOrConnectionString)
            {
            }
    
            /// <summary>
            ///     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.
            /// </summary>
            /// <param name="existingConnection">An existing connection to use for the new context.</param>
            /// <param name="model">The model that will back this context.</param>
            /// <param name="contextOwnsConnection">
            ///     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.
            /// </param>
            public IdentityDbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection)
                : base(existingConnection, model, contextOwnsConnection)
            {
            }
        }
    
        /// <summary>
        ///     DbContext which uses a custom user entity with a string primary key
        /// </summary>
        /// <typeparam name="TUser"></typeparam>
        public class IdentityDbContext<TUser> :
            IdentityDbContext<TUser, IdentityRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
            where TUser : IdentityUser
        {
            /// <summary>
            ///     Default constructor which uses the DefaultConnection
            /// </summary>
            public IdentityDbContext()
                : this("DefaultConnection")
            {
            }
    
            /// <summary>
            ///     Constructor which takes the connection string to use
            /// </summary>
            /// <param name="nameOrConnectionString"></param>
            public IdentityDbContext(string nameOrConnectionString)
                : this(nameOrConnectionString, true)
            {
            }
    
            /// <summary>
            ///     Constructor which takes the connection string to use
            /// </summary>
            /// <param name="nameOrConnectionString"></param>
            /// <param name="throwIfV1Schema">Will throw an exception if the schema matches that of Identity 1.0.0</param>
            public IdentityDbContext(string nameOrConnectionString, bool throwIfV1Schema)
                : base(nameOrConnectionString)
            {
                if (throwIfV1Schema && IsIdentityV1Schema(this))
                {
                    throw new InvalidOperationException(IdentityResources.IdentityV1SchemaError);
                }
            }
    
            /// <summary>
            ///     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.
            /// </summary>
            /// <param name="existingConnection">An existing connection to use for the new context.</param>
            /// <param name="model">The model that will back this context.</param>
            /// <param name="contextOwnsConnection">
            ///     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.
            /// </param>
            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<string>();
                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);
            }
        }
    
        /// <summary>
        ///     IdentityDbContext of IdentityUsers
        /// </summary>
        /// <typeparam name="TUser"></typeparam>
        /// <typeparam name="TRole"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TUserLogin"></typeparam>
        /// <typeparam name="TUserRole"></typeparam>
        /// <typeparam name="TUserClaim"></typeparam>
        public class IdentityDbContext<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim> : DbContext
            where TUser : IdentityUser<TKey, TUserLogin, TUserRole, TUserClaim>
            where TRole : IdentityRole<TKey, TUserRole>
            where TUserLogin : IdentityUserLogin<TKey>
            where TUserRole : IdentityUserRole<TKey>
            where TUserClaim : IdentityUserClaim<TKey>
        {
            /// <summary>
            ///     Default constructor which uses the "DefaultConnection" connectionString
            /// </summary>
            public IdentityDbContext()
                : this("DefaultConnection")
            {
            }
    
            /// <summary>
            ///     Constructor which takes the connection string to use
            /// </summary>
            /// <param name="nameOrConnectionString"></param>
            public IdentityDbContext(string nameOrConnectionString)
                : base(nameOrConnectionString)
            {
            }
    
            /// <summary>
            ///     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.
            /// </summary>
            /// <param name="existingConnection">An existing connection to use for the new context.</param>
            /// <param name="model">The model that will back this context.</param>
            /// <param name="contextOwnsConnection">
            ///     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.
            /// </param>
            public IdentityDbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection)
                : base(existingConnection, model, contextOwnsConnection)
            {
            }
    
    
            /// <summary>
            ///     EntitySet of Users
            /// </summary>
            public virtual IDbSet<TUser> Users { get; set; }
    
            /// <summary>
            ///     EntitySet of Roles
            /// </summary>
            public virtual IDbSet<TRole> Roles { get; set; }
    
            /// <summary>
            ///     If true validates that emails are unique
            /// </summary>
            public bool RequireUniqueEmail { get; set; }
    
            /// <summary>
            ///     Maps table names, and sets up relationships between the various user entities
            /// </summary>
            /// <param name="modelBuilder"></param>
            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<TUser>()
                    .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<TUserRole>()
                    .HasKey(r => new { r.UserId, r.RoleId })
                    .ToTable("AspNetUserRoles");
    
                modelBuilder.Entity<TUserLogin>()
                    .HasKey(l => new { l.LoginProvider, l.ProviderKey, l.UserId })
                    .ToTable("AspNetUserLogins");
    
                modelBuilder.Entity<TUserClaim>()
                    .ToTable("AspNetUserClaims");
    
                var role = modelBuilder.Entity<TRole>()
                    .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);
            }
    
            /// <summary>
            ///     Validates that UserNames are unique and case insenstive
            /// </summary>
            /// <param name="entityEntry"></param>
            /// <param name="items"></param>
            /// <returns></returns>
            protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry,
                IDictionary<object, object> items)
            {
                if (entityEntry != null && entityEntry.State == EntityState.Added)
                {
                    var errors = new List<DbValidationError>();
                    var user = entityEntry.Entity as TUser;
                    //check for uniqueness of user name and email
                    if (user != null)
                    {
                        if (Users.Any(u => String.Equals(u.UserName, user.UserName)))
                        {
                            errors.Add(new DbValidationError("User",
                                String.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateUserName, user.UserName)));
                        }
                        if (RequireUniqueEmail && Users.Any(u => String.Equals(u.Email, user.Email)))
                        {
                            errors.Add(new DbValidationError("User",
                                String.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateEmail, user.Email)));
                        }
                    }
                    else
                    {
                        var role = entityEntry.Entity as TRole;
                        //check for uniqueness of role name
                        if (role != null && Roles.Any(r => String.Equals(r.Name, role.Name)))
                        {
                            errors.Add(new DbValidationError("Role",
                                String.Format(CultureInfo.CurrentCulture, IdentityResources.RoleAlreadyExists, role.Name)));
                        }
                    }
                    if (errors.Any())
                    {
                        return new DbEntityValidationResult(entityEntry, errors);
                    }
                }
                return base.ValidateEntity(entityEntry, items);
            }
        }
    }

    上面的代码出自:

    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里面的结构不一致。

    找到如上代码,留文备用。

  • 相关阅读:
    Linux下GCC的使用
    Hadoop c++开发
    如何区别PeekMessage&GetMessage SendMessage&PostMessage
    二叉树的三种遍历方式的循环和递归的实现方式
    各种排序算法的代码
    各种排序算法的总结
    EAX、ECX、EDX、EBX寄存器的作用
    浮点型在内存当中的存储方式
    error LNK2001: 无法解析的外部符号
    线程通信
  • 原文地址:https://www.cnblogs.com/icyJ/p/IdentityDbContext.html
Copyright © 2020-2023  润新知