Entity-Framework Code First Migration With WebAPI 2.0 - Extending ASP.NET Identity Database

Here, in this article, we will see how to extend User Identity database in Web API using code first approach. Before going deep into this topic, let's see what Code First Migration actually is.

Prerequisite
  1. ASP.NET WEB API 2.0
  2. Entity Framework
Table Of Contents
  1. Working with Web API 2.0
  2. ASP.NET Identity
  3. Code First Approches.
  4. Updating Identity database Using Code First Migration
Introduction

In short, "Entity-Framework Code First Migration" helps in preserving the data even if your model changes. It will maintain the previous record with new record that is why we need this concept. You will get more understanding after checking the above link and reading this article.

ASP.NET Identity

ASP.NET Identity is the new membership system for ASP.NET applications. ASP.NET Identity makes it really easy to customize profile and add Login/ LogOut functionality to the application. If any one wants to learn more about ASP.NET Identity, I suggest you to check this link.

So, let's start our topic by creating a new ASP.NET Web API project as follows.


Now, click on "Change Authentication" button and select any one of the Authentication types.



Note

Please note that if you don't select any authentication, "No Authentication" will be selected by default, and there we will not get all the Identity related options. So, make sure you select the Individual Accounts while working on it.

Now,  you will find the following Controller and Models automatically added to your project.


Add "Entity Framework" from NuGet Package Manager.



Now, if you will check the AccountBindingModel.cs file, we have a Model called "RegistrationBindingModel" as follow.
  1. public class RegisterBindingModel    
  2.    {    
  3.        [Required]    
  4.        [Display(Name = "Email")]    
  5.        public string Email { getset; }    
  6.     
  7.        [Required]    
  8.        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]    
  9.        [DataType(DataType.Password)]    
  10.        [Display(Name = "Password")]    
  11.        public string Password { getset; }    
  12.          
  13.        [DataType(DataType.Password)]    
  14.        [Display(Name = "Confirm password")]    
  15.        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]    
  16.        public string ConfirmPassword { getset; }    
  17.    }    
Go to the  Account Controller and modify the Register Action method.
  1. // POST api/Account/Register  
  2.        [AllowAnonymous]  
  3.        [Route("Register")]  
  4.        public async Task<IHttpActionResult> Register(RegisterBindingModel model)  
  5.        {  
  6.            Dictionary<stringstring> dict = new Dictionary<stringstring>();  
  7.            if (!ModelState.IsValid)  
  8.            {  
  9.                return BadRequest(ModelState);  
  10.            }  
  11.   
  12.            var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };  
  13.   
  14.            IdentityResult result = await UserManager.CreateAsync(user, model.Password);  
  15.   
  16.            if (!result.Succeeded)  
  17.            {  
  18.                return GetErrorResult(result);  
  19.            }  
  20.            else  
  21.            {  
  22.                var showmessage = "User Register Successfully.";  
  23.   
  24.                dict.Add("Message", showmessage);  
  25.            }  
  26.   
  27.            return Ok(dict);  
  28.        }  
As we see, the API for Register User has been created, we can test the API in Postman like this.



As you know,  Code-First approach allows you to define Model classes as per the domain requirements, hence, you have complete control over the classes being written or implemented. 

In the code-first approach, the current user has to concentrate only on creating classes, models and writing code. The rest of the work like creating database, creating tables, assigning keys, etc. is looked over by the Entity Framework automatically. So, when we click on Register for the first time, it will map the Model defined in the Models folder and create a database for us as per our Model defined.

To see how the DBContext is written, we need to check the following Identity Model. 
  1. using System.Security.Claims;  
  2. using System.Threading.Tasks;  
  3. using Microsoft.AspNet.Identity;  
  4. using Microsoft.AspNet.Identity.EntityFramework;  
  5. using Microsoft.AspNet.Identity.Owin;  
  6.   
  7. namespace CFmigration.Models  
  8. {  
  9.     // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit https://go.microsoft.com/fwlink/?LinkID=317594 to learn more.  
  10.     public class ApplicationUser : IdentityUser  
  11.     {  
  12.         public string FirstName { getset; }  
  13.         public string LastName { getset; }  
  14.         public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)  
  15.         {  
  16.   
  17.             // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType  
  18.             var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);  
  19.             // Add custom user claims here  
  20.             return userIdentity;  
  21.         }  
  22.     }  
  23.   
  24.     public class ApplicationDbContext : IdentityDbContext<ApplicationUser>  
  25.     {  
  26.         public ApplicationDbContext()  
  27.             : base("DefaultConnection", throwIfV1Schema: false)  
  28.         {  
  29.         }  
  30.           
  31.         public static ApplicationDbContext Create()  
  32.         {  
  33.             return new ApplicationDbContext();  
  34.         }  
  35.     }  
  36. }  
And, if you will go to the peek definition of Identity User, you will find this.
  1. namespace Microsoft.AspNet.Identity.EntityFramework  
  2. {  
  3.     //  
  4.     // Summary:  
  5.     //     Default EntityFramework IUser implementation  
  6.     //  
  7.     // Type parameters:  
  8.     //   TKey:  
  9.     //  
  10.     //   TLogin:  
  11.     //  
  12.     //   TRole:  
  13.     //  
  14.     //   TClaim:  
  15.     public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>  
  16.         where TLogin : IdentityUserLogin<TKey>  
  17.         where TRole : IdentityUserRole<TKey>  
  18.         where TClaim : IdentityUserClaim<TKey>  
  19.     {  
  20.         //  
  21.         // Summary:  
  22.         //     Constructor  
  23.         public IdentityUser();  
  24.   
  25.         //  
  26.         // Summary:  
  27.         //     Email  
  28.         public virtual string Email { getset; }  
  29.         //  
  30.         // Summary:  
  31.         //     True if the email is confirmed, default is false  
  32.         public virtual bool EmailConfirmed { getset; }  
  33.         //  
  34.         // Summary:  
  35.         //     The salted/hashed form of the user password  
  36.         public virtual string PasswordHash { getset; }  
  37.         //  
  38.         // Summary:  
  39.         //     A random value that should change whenever a users credentials have changed (password  
  40.         //     changed, login removed)  
  41.         public virtual string SecurityStamp { getset; }  
  42.         //  
  43.         // Summary:  
  44.         //     PhoneNumber for the user  
  45.         public virtual string PhoneNumber { getset; }  
  46.         //  
  47.         // Summary:  
  48.         //     True if the phone number is confirmed, default is false  
  49.         public virtual bool PhoneNumberConfirmed { getset; }  
  50.         //  
  51.         // Summary:  
  52.         //     Is two factor enabled for the user  
  53.         public virtual bool TwoFactorEnabled { getset; }  
  54.         //  
  55.         // Summary:  
  56.         //     DateTime in UTC when lockout ends, any time in the past is considered not locked  
  57.         //     out.  
  58.         public virtual DateTime? LockoutEndDateUtc { getset; }  
  59.         //  
  60.         // Summary:  
  61.         //     Is lockout enabled for this user  
  62.         public virtual bool LockoutEnabled { getset; }  
  63.         //  
  64.         // Summary:  
  65.         //     Used to record failures for the purposes of lockout  
  66.         public virtual int AccessFailedCount { getset; }  
  67.         //  
  68.         // Summary:  
  69.         //     Navigation property for user roles  
  70.         public virtual ICollection<TRole> Roles { get; }  
  71.         //  
  72.         // Summary:  
  73.         //     Navigation property for user claims  
  74.         public virtual ICollection<TClaim> Claims { get; }  
  75.         //  
  76.         // Summary:  
  77.         //     Navigation property for user logins  
  78.         public virtual ICollection<TLogin> Logins { get; }  
  79.         //  
  80.         // Summary:  
  81.         //     User ID (Primary Key)  
  82.         public virtual TKey Id { getset; }  
  83.         //  
  84.         // Summary:  
  85.         //     User name  
  86.         public virtual string UserName { getset; }  
  87.     }  
  88. }  


 Finally, if we check our Server Explorer, we will find the following things.



Now, go to the ASPNETUser Table and see the table structure.

 

Now, if we check our data, we will find this here.


As the default initializer class used by Code-First approach is CreateDatabaseIfNotExists, so when the application starts, this initializer checks for the required Model database. If it is not found, it will create the database.

So now, the main tragedy will come when we need to update or add some more columns in this database. Suppose our manager told to add more fields (First Name and Last Name) for registration.

Here comes the main thing about Entity Framework Code First Migration.

What is this Code First Migration and why did we need this?

Entity Framework 4.3 has introduced a migration tool that automatically updates the database schema when your Model changes without losing any existing data or other database objects. It uses a new database initializer called MigrateDatabaseToLatestVersion.

In short, "Entity-Framework Code First Migration" helps in preserving the earlier data even if your Model changes to update your database scheme. It will maintain the previous record with a new record that is why we need this concept. You will get more understanding after checking the above link and reading this article.

How to do Code First Migration?
 
Before enabling migratiion, now change your Model and the properties you want there.

 
Now, go to the IdentityModel and add the following  two properties under ApplicationUser, as shown below.
  1. using System.Security.Claims;  
  2. using System.Threading.Tasks;  
  3. using Microsoft.AspNet.Identity;  
  4. using Microsoft.AspNet.Identity.EntityFramework;  
  5. using Microsoft.AspNet.Identity.Owin;  
  6.   
  7. namespace CFmigration.Models  
  8. {  
  9.     // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit https://go.microsoft.com/fwlink/?LinkID=317594 to learn more.  
  10.     public class ApplicationUser : IdentityUser  
  11.     {  
  12.         public string FirstName { getset; }  
  13.         public string LastName { getset; }  
  14.         public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)  
  15.         {  
  16.   
  17.             // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType  
  18.             var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);  
  19.             // Add custom user claims here  
  20.             return userIdentity;  
  21.         }  
  22.     }  
  23.   
  24.     public class ApplicationDbContext : IdentityDbContext<ApplicationUser>  
  25.     {  
  26.         public ApplicationDbContext()  
  27.             : base("DefaultConnection", throwIfV1Schema: false)  
  28.         {  
  29.         }  
  30.           
  31.         public static ApplicationDbContext Create()  
  32.         {  
  33.             return new ApplicationDbContext();  
  34.         }  
  35.     }  
  36. }  
Now, for saving these newly changed data in DB, please modify the Registration method.
  1. // POST api/Account/Register  
  2. [AllowAnonymous]  
  3. [Route("Register")]  
  4. public async Task<IHttpActionResult> Register(RegisterBindingModel model)  
  5. {  
  6.     Dictionary<stringstring> dict = new Dictionary<stringstring>();  
  7.     if (!ModelState.IsValid)  
  8.     {  
  9.         return BadRequest(ModelState);  
  10.     }  
  11.   
  12.     var user = new ApplicationUser() { UserName = model.Email, Email = model.Email,FirstName=model.FirstName,LastName=model.LastName };  
  13.   
  14.     IdentityResult result = await UserManager.CreateAsync(user, model.Password);  
  15.   
  16.     if (!result.Succeeded)  
  17.     {  
  18.         return GetErrorResult(result);  
  19.     }  
  20.     else  
  21.     {  
  22.         var showmessage = "User Register Successfully.";  
  23.   
  24.         dict.Add("Message", showmessage);  
  25.     }  
  26.   
  27.     return Ok(dict);  
  28. }  

Now, all our Models have changed. For enabling migration, we should follow the below three steps.

  1. Enable-Migrations
  2. Add-Migration <name>
  3. Update-Database
STEP 1 - Enable Migration.

After enabling migration, you will see the Migrations folder with the following details.



STEP 2 - Add-Migration <name>



Once this command executes, it will add the following initial file and add its code. Now, the third last step is to update the database.

STEP 3 - Update Database



Now, we will upade the database. If you want to see the update, just go to the Server Explorer and check that.



Hence, we saw how the table is updated without affecting the previous data using Code-First approach.

Now, let's test this API using Postman.



Now, if we check the record, we will find the following result.



Conclusion

Thus, we can use Code-First migration to extend the Identity DB.

I hope you understood the concept. If you have any queries or suggestions regarding this, you can write it in the comments box.

Up Next
    Ebook Download
    View all
    Learn
    View all