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 [email protected]", 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里面的结构不一致。

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

时间: 2024-08-01 10:30:55

Microsoft.AspNet.Identity.EntityFramework/IdentityDbContext.cs的相关文章

Asp.net Identity 系列之 怎样修改Microsoft.AspNet.Identity.EntityFramework.IdentityUser 的 Id 字段的数据类型

这篇博客我们来学习如何将AspNetUsers 表的Id 字段 的类型由nvarchar(128) 改为Int 并且子增长 1.为什么要修改 如果你运行过 Asp.net mvc 示例项目,你好会发现 AspNetUsers 表的Id是Nvarchar(128) 类型,值为GUID,不可否认使用GUID来做主键进行主外键关联会增加数据安全性(个人看法),但是非常不利于查询,可读性不够,因此我们尝试着去改为Int类型. 先看一下修改后的效果: 2.修改前分析 查看数据库结构我们知道要修改的表有这样

从Microsoft.AspNet.Identity看微软推荐的一种MVC的分层架构

Microsoft.AspNet.Identity简介 Microsoft.AspNet.Identity是微软在MVC 5.0中新引入的一种membership框架,和之前ASP.NET传统的membership以及WebPage所带来的SimpleMembership(在MVC 4中使用)都有所不同. Microsoft.AspNet.Identity是符合微软开放Owin标准里面Security标准的一种实现.且在MVC 5中默认使用EntityFramework作为Microsoft.A

Microsoft.AspNet.Identity 自定义使用现有的表—登录实现

Microsoft.AspNet.Identity是微软新引入的一种membership框架,也是微软Owin标准的一个实现.Microsoft.AspNet.Identity.EntityFramework则是Microsoft.AspNet.Identity的数据提供实现.但是在使用此框架的时候存在一些问题,如果是全新的项目还可以使用它默认提供的表名,字段名等.但是如果是在一些老的数据库上应用这个框架就比较麻烦了.所以我们实现一个自己的Microsoft.AspNet.Identity.En

Microsoft.AspNet.Identity 2.0 用账号或者邮件作为登陆方式

创建一个默认的MVC4.0的项目工程,默认的登陆方式是邮件登陆,那么有没办法改为用账号登陆? 我们来看下默认的登陆Action [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); }// This doesn

Microsoft.AspNet.Identity 重置密码

原文:Microsoft.AspNet.Identity 重置密码 重置密码:先生成重置密码的Token,然后调用ResetPassword方法重置密码,密码要符合规则.. ApplicationUserManager UserManager => _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); string token = UserManager.Generat

Microsoft.AspNet.Identity: UserID用整型数据表示, 而不是GUID

http://stackoverflow.com/questions/19553424/how-to-change-type-of-id-in-microsoft-aspnet-identity-entityframework-identityus

AspNet Identity and IoC Container Registration

https://github.com/trailmax/IoCIdentitySample TL;DR: Registration code for Autofac, for SimpleInjector, for Unity. Tony Mackay has an alternative walk-through of a very similar process but with Autofac Part 2: Sending Emails in Asp.Net Identity using

mvc core2.1 Identity.EntityFramework Core 用户Claims查看(七)

添加角色属性查看 Views ->Shared->_Layout.cshtml <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a asp-area="" asp-controller="Home" asp-action="Index">Home<

命名空间“Microsoft.AspNet”中不存在类型或命名空间名“Mvc”

问题: 错误 CS0234 命名空间"Microsoft.AspNet"中不存在类型或命名空间名"Mvc"(是否缺少程序集引用?) 解决方案: 打开文件夹 Users\<CurrentUser>\AppData\Local\Microsoft\VisualStudio\<version> 删除文件夹 ComponentModelCache 重启 Visual Studio.