ASP.NET Identity with EF Database First MVC5
Solution 1
It should be possible to use the identity system with POCO and Database First, but you'll have to make a couple of tweaks:
- Update the .tt-file for POCO generation to make the entity classes
partial
. That will make it possible for you to supply additional implementation in a separate file. - Make a partial implementation of the
User
class in another file
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).
Solution 2
My steps are very similar but I wanted to share.
1) Create a new MVC5 project
2) Create a new Model.edmx. Even if it's a new database and has no tables.
3) Edit web.config and replace this generated 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.
Solution 3
EDIT: ASP.NET Identity with EF Database First for MVC5 CodePlex Project Template.
I wanted to use an existing database and create relationships with ApplicationUser. This is how I did it using SQL Server but the same idea would probably work with any DB.
- Create an MVC Project
- Open the DB listed under the DefaultConnection in Web.config. It will be called (aspnet-[timestamp] or something like that.)
- Script the database tables.
- Insert the scripted tables into existing database in SQL Server Management Studio.
- Customize and add relationships to ApplicationUser (if necessary).
- Create new Web Project > MVC > DB First Project > Import DB with EF ... Excluding the Identity Classes you inserted.
- In IdentityModels.cs change the ApplicationDbContext
:base("DefaltConnection")
to use your project's DbContext.
Edit: Asp.Net Identity Class Diagram
Solution 4
IdentityUser
is worthless here because it's the code-first object used by the UserStore
for authentication. After defining my own User
object, I implemented a partial class that implements IUser
which is used by the UserManager
class. I wanted my Id
s to be int
instead of string so I just return the UserID's toString(). Similarly I wanted n
in Username
to be uncapitalized.
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
. It's only an interface used by the UserManager
. So if you want to define a different "IUser" you would have to rewrite this class to use your own implementation.
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
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.
public AccountController()
: this(new UserManager<User>(new MyUserStore<User>(new MyAppEntities())))
{
}
Now logging in should work with your own tables.
Solution 5
Take a look at this project on GitHub: https://github.com/KriaSoft/AspNet.Identity
Which includes:
- SQL Database Project Template for ASP.NET Identity 2.0
- Entity Framework Database-First Provider(s)
- Source Code and Samples
Also see: How to create Database-First provider for ADO.NET Identity
Patrick T
Updated on March 09, 2020Comments
-
Patrick T about 4 years
Is it possible to use the new Asp.net Identity with Database First and 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.
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.
3) Upon saving the EDMX, the Database First POCO generator will auto create a User class. 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.
I guess a possible solution is to edit my POCO Generation Classes to have my User class inherit from IUser?
Or is ASP.NET Identity only compatible with Code First Design?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Update: Following Anders Abel's suggestion below, this is what I did. 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.
namespace MVC5.DBFirst.Entity { public partial class AspNetUser : IdentityUser { } }
2) I changed my DataContext to inherit from IdentityDBContext instead of 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.
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). Note that every time you update your EDMX and regenerate the DBContext and Entity classes, you'll have to set this back to this.
override public string Id { get; set; } override public string UserName { get; set; } override public string PasswordHash { get; set; } override public string SecurityStamp { get; set; }
-
Patrick T over 10 yearsThe issue isn't DBContext, but that UserManager and RoleManager expect a class that inherits from Microsoft.AspNet.Identity.EntityFramework.IdentityUser
-
Patrick T over 10 yearspublic class IdentityDbContext<TUser> : DbContext where TUser : Microsoft.AspNet.Identity.EntityFramework.IdentityUser. When using database first, the generated entity classes do not inherit from any base classes.
-
Patrick T over 10 yearsThanks. I'll have to give this a try and report if it works out.
-
Patrick T over 10 yearsI tried what you mentioned. See my post for updated info... but the solution wasn't very elegant :/
-
stink over 10 yearsThen just exclude them from the database when you generate the classes with the entity framework.
-
Patrick T over 10 yearsIf you exclude the Identity tables from the EDMX, then you will lose the Navigation properties in other classes that have foreign keys to your UserID
-
stink over 10 yearsDid you figure it out? Why are you reluctant to move to code first?
-
Patrick T over 10 yearsI'm not reluctant to move to code first... It's just that in some scenarios and companies, the db admin creates the base tables, not the coder.
-
Phil over 10 yearsI've been having just the same problem. It seems that documentation on DB-first is very sparse. This is a nice suggestion but I think you're right, it doesn't quite work
-
user20358 about 10 yearsIs there any solution as yet that is not a hack?
-
Hassen Ch. over 9 yearsthis solved a problem, I couldn't see the application user in the database, but after replacing the default connection, it worked.
-
Usman Khalid almost 9 yearsI am using Onion Architecture and all of POCOs are in Core. There it is not recommended to use IUser. So anyother solution?
-
Naz Ekin over 8 yearsI recently had a chance to implement this, and for some reason ( I believe because of the 3.0 update of the identity ) I was not able to implement the login by inheriting IdentityUser and then overriding the properties; but writing a custom UserStore and inheriting IUser worked fine; Just giving an update, maybe someone finds this useful.
-
Badhon Jain over 8 yearsI tried everything you mentioned in your blog twice, it didn't work out for me.
-
Daniel Eagle over 8 years@Badhon I'm very sorry the instructions in my blog post didn't work out for you. I've had countless people express their thanks as they've found success following my article. Always remember that if Microsoft updates something it can affect the outcome. I wrote the article for ASP.NET MVC 5 with Identity Framework 2.0. Anything beyond that may experience problems but so far I've received very recent comments indicating success. I'd love to hear more about your problem.
-
Badhon Jain over 8 yearsI will try to follow once again, the problem I faced is I could not use my custom database, it used the auto built database. Anyway, I didn't mean to say something wrong with your article. Thanks for sharing your knowledge.
-
Daniel Eagle over 8 years@Badhon No worries my friend, I never felt you were saying anything was wrong with the article. We all have unique situations with various edge cases so sometimes what works for others may not necessarily work for us. I'm hope you were able to solve your problem.
-
DespeiL about 8 yearsCan you give link for all interface implementation or for full project?
-
Ken over 4 years@PatrickTran I know the post is old, you can have your dbcontext inherit from identityDbContext<T> and then you have all the access you need to those fields.
-
user8964654 over 4 yearsis there a specific reason why you used a partial class here?
-
jamesSampica over 4 yearsIf you're using an edmx to generate your models you must use a partial class. If you're doing code first then you may omit this