How does a new ASP.NET MVC 5 application know how to create a database and how does the Account Controller access the database?

user1943020 picture user1943020 · Apr 17, 2014 · Viewed 35.3k times · Source

I created an ASP.NET MVC 5 Application using Visual Studio 2013 Update 2. In the application, I have an Account controller. It's different from what I am used to and does not contain an instantiation of dbcontext.

public class AccountController : Controller
{
    private ApplicationUserManager _userManager;

    public AccountController()
    {
    }

    public AccountController(ApplicationUserManager userManager)
    {
        UserManager = userManager;
    }

    public ApplicationUserManager UserManager {
        get
        {
            return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }

My web.config that is created by default has a connection string like this:

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

Can someone explain to me how the application knows to create a database for this application when it starts for the first time?

Also, on subsequent starts, does it use Entity Framework to access the Identity tables to do the authentication?

Answer

Dave Alperovich picture Dave Alperovich · Apr 19, 2014

1) WHAT'S GOING ON HERE:

When you create a new MVC 5 application and choose "Individual User Accounts", a new ASP.NET Identity Provider is included which uses Entity Framework 6 Code-First.

Microsoft has adopted EF-Code-First to make Identity as customizable as possible.

When Identity is accessed for the first time, Entity Framework checks to see if the database exists. Unless configured otherwise, it uses the "DefaultConnection" to find the identity database. If the database does not exist when Identity is called, EF automatically created the database.

Notice your connection string contains

`AttachDbFilename=|DataDirectory|\aspnet-WebApplication3-20140417072624.mdf`

If you open your App_Data Folder, you should have a aspnet-WebApplication3-20140417072624.mdf file.

If you double click on this .mdf file, the VS2013 Server Explorer will open your DB. If you have already attempted to access any Identity functionality, you will these tables created:

  • _MigrationHistory
  • ASPNetRoles
  • ASPNetUserClaims
  • ASPNetUserLogins
  • ASPNetUsers

By default, your app is configured to use SQL Server Compact (MDF file) so you don't have to have an actual SQL Server Instance running. All of this is customizable. The name of your MDF file, the schema of Identity Database, the choice of SQL Compact vs an actual SQL Server instance. Change your Connection String, or create a new one and pass this new connection to your context.


2) WHERE IS MY CONTEXT?

All this is well and good, but an important question you asked is basically "Where is my context?", and the just as relevant implied questions regarding how you can further customize your DB or alter validation logic.

You will notice that your project references Microsoft.AspNet.Identity.EntityFramework. This assembly is an implementation of IdentityDBContext<TUser> and implentation of UserManager Class.

Open your AccountController, and notice the constructor has UserManager object passed which in turn has a new UserStore object passed, which gets passed a ApplicationDbContext.

    public AccountController()
        : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))

The ApplicationDbContext is defined in your Models Folder. Inside that folder, you will find an IdentityModels.cs file. Open it and you will see

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
}

This is where your Identity Context is assigned. you can change the connection name passed to the ApplicationDbContext constructor, or define and use a different context in your account controller.


3) HOW DO I CUSTOMIZE MY IDENTITY SCHEMA?

Another class defined IN IdentityModels.cs file is the ApplicationUser class which inherits from IdentityUser class.

public class ApplicationUser : IdentityUser
{
}

Any properties you add to this class will be persisted in your ASPNetUsers Table. The rest of the schema is defined in IdentityDbContext class. So, while you can add more tables (e.g. Privileges) to your Identity Schema by adding a DBSet to the Context Definition,

public DBSet<Privileges> { get; set; }

Altering other tables (Roles, Claims, etc) is also possible, but far more involved. For example, to customize the Roles table, you would have to implement a NewIdentityRole inheriting from IdentityRole and add it's relationship by overriding the OnModelCreating() method for your Context.

This article on Customizing Roles Tables does a good job of describing the steps involved. Even here, you will find that there is significant trouble invested into simply ADDING new columns. Removing tables or columns from the original schema created in the IdentityDbContext class is probably as much trouble as creating your own implementation of IdentityDbContext class.