简体   繁体   English

使用EF Database First MVC5的ASP.NET标识

[英]ASP.NET Identity with EF Database First MVC5

Is it possible to use the new Asp.net Identity with Database First and EDMX? 是否可以将新的Asp.net标识与Database First和EDMX一起使用? Or only with code first? 或者只使用代码?

Here's what I did: 这是我做的:

1) I made a new MVC5 Project and had the new Identity create the new User and Roles tables in my database. 1)我创建了一个新的MVC5项目并让新的Identity在我的数据库中创建了新的User和Roles表。

2) I then opened my Database First EDMX file and dragged in the new Identity Users table since I have other tables that relate to it. 2)然后我打开了我的Database First EDMX文件并拖入了新的Identity Users表,因为我有其他与之相关的表。

3) Upon saving the EDMX, the Database First POCO generator will auto create a User class. 3)保存EDMX后,Database First POCO生成器将自动创建User类。 However, UserManager and RoleManager expects a User class inheriting from the new Identity namespace (Microsoft.AspNet.Identity.IUser), so using the POCO User class won't work. 但是,UserManager和RoleManager需要从新的Identity命名空间(Microsoft.AspNet.Identity.IUser)继承User类,因此使用POCO User类将不起作用。

I guess a possible solution is to edit my POCO Generation Classes to have my User class inherit from IUser? 我想一个可能的解决方案是编辑我的POCO生成类以使我的User类继承自IUser?

Or is ASP.NET Identity only compatible with Code First Design? 或者ASP.NET Identity仅与Code First Design兼容?

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++

Update: Following Anders Abel's suggestion below, this is what I did. 更新:根据Anders Abel的建议,这就是我所做的。 It work's, but I'm wondering if there is a more elegant solution. 它的工作原理,但我想知道是否有更优雅的解决方案。

1) I extended my entity User class by creating a partial class within the same namespace as my auto generated entities. 1)我通过在与自动生成的实体相同的命名空间中创建一个部分类来扩展我的实体User类。

namespace MVC5.DBFirst.Entity
{
    public partial class AspNetUser : IdentityUser
    {
    }
}

2) I changed my DataContext to inherit from IdentityDBContext instead of DBContext. 2)我将DataContext更改为继承IdentityDBContext而不是DBContext。 Note that every time you update your EDMX and regenerate the DBContext and Entity classes, you'll have to set this back to this. 请注意,每次更新EDMX并重新生成DBContext和Entity类时,都必须将其设置为此。

 public partial class MVC5Test_DBEntities : IdentityDbContext<AspNetUser>  //DbContext

3) Within your auto generated User entity class, you must add the override keyword to the following 4 fields or comment these fields out since they are inherited from IdentityUser (Step 1). 3)在自动生成的User实体类中,必须将override关键字添加到以下4个字段中,或者将这些字段注释掉,因为它们是从IdentityUser继承的(步骤1)。 Note that every time you update your EDMX and regenerate the DBContext and Entity classes, you'll have to set this back to this. 请注意,每次更新EDMX并重新生成DBContext和Entity类时,都必须将其设置为此。

    override public string Id { get; set; }
    override public string UserName { get; set; }
    override public string PasswordHash { get; set; }
    override public string SecurityStamp { get; set; }

It should be possible to use the identity system with POCO and Database First, but you'll have to make a couple of tweaks: 应该可以将身份系统与POCO和Database First一起使用,但您必须进行一些调整:

  1. Update the .tt-file for POCO generation to make the entity classes partial . 更新.tt文件以生成POCO以使实体类成为partial That will make it possible for you to supply additional implementation in a separate file. 这将使您可以在单独的文件中提供其他实现。
  2. Make a partial implementation of the User class in another file 在另一个文件中部分实现User

partial User : IUser
{
}

That will make the User class implement the right interface, without touching the actual generated files (editing generated files is always a bad idea). 这将使User类实现正确的接口,而不触及实际生成的文件(编辑生成的文件总是一个坏主意)。

My steps are very similar but I wanted to share. 我的步骤非常相似,但我想分享。

1) Create a new MVC5 project 1)创建一个新的MVC5项目

2) Create a new Model.edmx. 2)创建一个新的Model.edmx。 Even if it's a new database and has no tables. 即使它是一个新的数据库,也没有表。

3) Edit web.config and replace this generated connectionstring: 3)编辑web.config并替换生成的connectionstring:

<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-SSFInventory-20140521115734.mdf;Initial Catalog=aspnet-SSFInventory-20140521115734;Integrated Security=True" providerName="System.Data.SqlClient" />

with this connectionstring: 使用此连接字符串:

<add name="DefaultConnection" connectionString="Data Source=.\SQLExpress;database=SSFInventory;integrated security=true;" providerName="System.Data.SqlClient" />

Afterwards, build and run the application. 然后,构建并运行应用程序。 Register a user and then the tables will be created. 注册用户,然后将创建表。

EDIT: ASP.NET Identity with EF Database First for MVC5 CodePlex Project Template. 编辑: 使用EF数据库的ASP.NET身份首先用于MVC5 CodePlex项目模板。


I wanted to use an existing database and create relationships with ApplicationUser. 我想使用现有数据库并与ApplicationUser建立关系。 This is how I did it using SQL Server but the same idea would probably work with any DB. 这就是我使用SQL Server的方式,但同样的想法可能适用于任何数据库。

  1. Create an MVC Project 创建一个MVC项目
  2. Open the DB listed under the DefaultConnection in Web.config. 打开Web.config中DefaultConnection下列出的数据库。 It will be called (aspnet-[timestamp] or something like that.) 它将被调用(aspnet- [timestamp]或类似的东西。)
  3. Script the database tables. 编写数据库表的脚本。
  4. Insert the scripted tables into existing database in SQL Server Management Studio. 将脚本表插入SQL Server Management Studio中的现有数据库。
  5. Customize and add relationships to ApplicationUser (if necessary). 自定义并添加与ApplicationUser的关系(如有必要)。
  6. Create new Web Project > MVC > DB First Project > Import DB with EF ... Excluding the Identity Classes you inserted. 创建新的Web项目> MVC> DB第一个项目>使用EF导入数据库...排除您插入的标识类。
  7. In IdentityModels.cs change the ApplicationDbContext :base("DefaltConnection") to use your project's DbContext. IdentityModels.cs中,更改ApplicationDbContext :base("DefaltConnection")以使用项目的DbContext。

Edit: Asp.Net Identity Class Diagram 编辑: Asp.Net Identity Class Diagram 在此输入图像描述

IdentityUser is worthless here because it's the code-first object used by the UserStore for authentication. IdentityUser在这里毫无价值,因为它是UserStore用于身份验证的代码优先对象。 After defining my own User object, I implemented a partial class that implements IUser which is used by the UserManager class. 在定义了我自己的User对象之后,我实现了一个实现IUser的部分类,它由UserManager类使用。 I wanted my Id s to be int instead of string so I just return the UserID's toString(). 我希望我的Idint而不是string,所以我只返回UserID的toString()。 Similarly I wanted n in Username to be uncapitalized. 同样,我希望Username n不被大写。

public partial class User : IUser
{

    public string Id
    {
        get { return this.UserID.ToString(); }
    }

    public string UserName
    {
        get
        {
            return this.Username;
        }
        set
        {
            this.Username = value;
        }
    }
}

You by no means need IUser . 你绝不需要IUser It's only an interface used by the UserManager . 它只是UserManager使用的接口。 So if you want to define a different "IUser" you would have to rewrite this class to use your own implementation. 因此,如果要定义不同的“IUser”,则必须重写此类以使用自己的实现。

public class UserManager<TUser> : IDisposable where TUser: IUser

You now write your own UserStore which handles all of the storage of users, claims, roles, etc. Implement the interfaces of everything that the code-first UserStore does and change where TUser : IdentityUser to where TUser : User where "User" is your entity object 您现在编写自己的UserStore来处理用户,声明,角色等的所有存储。实现代码优先UserStore所做的一切的接口,并将where TUser : IdentityUser更改到where TUser : User所在的用户所在的位置实体对象

public class MyUserStore<TUser> : IUserLoginStore<TUser>, IUserClaimStore<TUser>, IUserRoleStore<TUser>, IUserPasswordStore<TUser>, IUserSecurityStampStore<TUser>, IUserStore<TUser>, IDisposable where TUser : User
{
    private readonly MyAppEntities _context;
    public MyUserStore(MyAppEntities dbContext)
    { 
        _context = dbContext; 
    }

    //Interface definitions
}

Here are a couple examples on some of the interface implementations 以下是一些接口实现的几个示例

async Task IUserStore<TUser>.CreateAsync(TUser user)
{
    user.CreatedDate = DateTime.Now;
    _context.Users.Add(user);
    await _context.SaveChangesAsync();
}

async Task IUserStore<TUser>.DeleteAsync(TUser user)
{
    _context.Users.Remove(user);
    await _context.SaveChangesAsync();
}

Using the MVC 5 template, I changed the AccountController to look like this. 使用MVC 5模板,我将AccountController更改为如下所示。

public AccountController()
        : this(new UserManager<User>(new MyUserStore<User>(new MyAppEntities())))
{
}

Now logging in should work with your own tables. 现在登录应该适用于您自己的表。

Take a look at this project on GitHub: https://github.com/KriaSoft/AspNet.Identity 在GitHub上看看这个项目: https//github.com/KriaSoft/AspNet.Identity

Which includes: 包括:

  • SQL Database Project Template for ASP.NET Identity 2.0 ASP.NET Identity 2.0的SQL数据库项目模板
  • Entity Framework Database-First Provider(s) 实体框架数据库第一提供商
  • Source Code and Samples 源代码和样本

在此输入图像描述

Also see : How to create Database-First provider for ADO.NET Identity 另请参阅如何为ADO.NET标识创建数据库优先提供程序

I spent several hours working through this and finally found a solution which I have shared on my blog here . 我花了几个小时通过这个工作,终于找到了,我已经在我的博客共享的解决方案在这里 Basically, you need to do everything said in stink 's answer but with one additional thing: ensuring Identity Framework has a specific SQL-Client connection string on top of the Entity Framework connection string used for your application entities. 基本上,你需要做一些在stink的答案中说的话,但还有一件事:确保Identity Framework在用于你的应用程序实体的Entity Framework连接字符串之上有一个特定的SQL-Client连接字符串。

In summary, your application will use a connection string for Identity Framework and another for your application entities. 总之,您的应用程序将使用Identity Framework的连接字符串和您的应用程序实体的另一个字符串。 Each connection string is of a different type. 每个连接字符串都是不同的类型。 Read my blog post for a full tutorial. 阅读我的博客文章,获取完整的教程。

Good question. 好问题。

I'm more of a database-first person. 我更像是数据库第一人。 The code first paradigm seems to loosey-goosey to me, and the "migrations" seem too error prone. 代码第一范式对我来说似乎是松散的,而且“迁移”似乎太容易出错。

I wanted to customize the aspnet identity schema, and not be bothered with migrations. 我想自定义aspnet身份模式,而不是被迁移困扰。 I'm well versed with Visual Studio database projects (sqlpackage, data-dude) and how it does a pretty good job at upgrading schemas. 我非常精通Visual Studio数据库项目(sqlpackage,data-dude)以及它如何在升级模式方面做得非常好。

My simplistic solution is to: 我的简单解决方案是:

1) Create a database project that mirrors the aspnet identity schema 2) use the output of this project (.dacpac) as a project resource 3) deploy the .dacpac when needed 1)创建一个镜像aspnet身份模式的数据库项目2)使用此项目的输出(.dacpac)作为项目资源3)在需要时部署.dacpac

For MVC5, modifying the ApplicationDbContext class seems to get this going... 对于MVC5,修改ApplicationDbContext类似乎可以实现这一目标......

1) Implement IDatabaseInitializer 1)实现IDatabaseInitializer

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IDatabaseInitializer<ApplicationDbContext> { ... }

2) In the constructor, signal that this class will implement database initialization: 2)在构造函数中,表示此类将实现数据库初始化:

Database.SetInitializer<ApplicationDbContext>(this);

3) Implement InitializeDatabase : 3)实现InitializeDatabase

Here, I chose to use DacFX and deploy my .dacpac 在这里,我选择使用DacFX并部署我的.dacpac

    void IDatabaseInitializer<ApplicationDbContext>.InitializeDatabase(ApplicationDbContext context)
    {
        using (var ms = new MemoryStream(Resources.Binaries.MainSchema))
        {
            using (var package = DacPackage.Load(ms, DacSchemaModelStorageType.Memory))
            {
                DacServices services = new DacServices(Database.Connection.ConnectionString);
                var options = new DacDeployOptions
                {
                    VerifyDeployment = true,
                    BackupDatabaseBeforeChanges = true,
                    BlockOnPossibleDataLoss = false,
                    CreateNewDatabase = false,
                    DropIndexesNotInSource = true,
                    IgnoreComments = true,

                };
                services.Deploy(package, Database.Connection.Database, true, options);
            }
        }
    }

We have a Entity Model DLL project where we keep our model class. 我们有一个实体模型DLL项目,我们保留我们的模型类。 We also keep a Database Project with all of database scripts. 我们还使用所有数据库脚本保留数据库项目。 My approach was as follows 我的方法如下

1) Create your own project that has the EDMX using database first 1)首先使用数据库创建自己的EDMX项目

2) Script the tables in your db, I used VS2013 connected to localDB (Data Connections) and copied the script to database project, add any custom columns, eg BirthDate [DATE] not null 2)编写数据库中的表,我使用VS2013连接到localDB(数据连接)并将脚本复制到数据库项目,添加任何自定义列,例如BirthDate [DATE] not null

3) Deploy the database 3)部署数据库

4) Update the Model (EDMX) project Add to the Model project 4)更新模型(EDMX)项目添加到模型项目

5) Add any custom columns to the application class 5)将任何自定义列添加到应用程序类

public class ApplicationUser : IdentityUser
{
    public DateTime BirthDate { get; set; }
}

In the MVC project AccountController added the following: 在MVC项目中,AccountController添加了以下内容:

The Identity Provider want a SQL Connection String for it to work, to keep only 1 connection string for the database, extract the provider string from EF connection string 身份提供程序需要SQL连接字符串才能工作,只保留数据库的1个连接字符串,从EF连接字符串中提取提供程序字符串

public AccountController()
{
   var connection = ConfigurationManager.ConnectionStrings["Entities"];
   var entityConnectionString = new EntityConnectionStringBuilder(connection.ConnectionString);
        UserManager =
            new UserManager<ApplicationUser>(
                new UserStore<ApplicationUser>(
                    new ApplicationDbContext(entityConnectionString.ProviderConnectionString)));
}

I found that @JoshYates1980 does have the simplest answer. 我发现@JoshYates1980确实有最简单的答案。

After a series trials and errors I did what Josh suggested and replaced the connectionString with my generated DB connection string. 经过一系列的试验和错误后,我做了Josh建议的事情,并用我生成的数据库连接字符串替换了connectionString what I was confused about originally was the following post: 我最初感到困惑的是以下帖子:

How to add ASP.NET MVC5 Identity Authentication to existing database 如何将ASP.NET MVC5身份验证添加到现有数据库

Where the accepted answer from @Win stated to change the ApplicationDbContext() connection name. 来自@Win的接受答案声明要更改ApplicationDbContext()连接名称。 This is a little vague if you are using Entity and a Database/Model first approach where the database connection string is generated and added to the Web.config file. 如果您使用Entity和数据库/模型第一种方法生成数据库连接字符串并将其添加到Web.config文件,则这有点模糊。

The ApplicationDbContext() connection name is mapped to the default connection in the Web.config file. ApplicationDbContext()连接名称映射Web.config文件中的默认连接。 Therefore, Josh's method works best, but to make the ApplicationDbContext() more readable I would suggest changing the name to your database name as @Win originally posted, making sure to change the connectionString for the "DefaultConnection" in the Web.config and comment out and/or remov the Entity generated database include. 因此,Josh的方法效果最好,但为了使ApplicationDbContext()更具可读性,我建议将名称更改为@Win最初发布的数据库名称,确保更改Web.config的“DefaultConnection”的connectionString并注释out和/或删除实体生成的数据库包括。

Code Examples: 代码示例:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM