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
- ASP.NET WEB API 2.0
- Entity Framework
Table Of Contents
- Working with Web API 2.0
- ASP.NET Identity
- Code First Approches.
- 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.
- public class RegisterBindingModel
- {
- [Required]
- [Display(Name = "Email")]
- public string Email { get; set; }
-
- [Required]
- [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
- [DataType(DataType.Password)]
- [Display(Name = "Password")]
- public string Password { get; set; }
-
- [DataType(DataType.Password)]
- [Display(Name = "Confirm password")]
- [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
- public string ConfirmPassword { get; set; }
- }
Go to the Account Controller and modify the Register Action method.
-
- [AllowAnonymous]
- [Route("Register")]
- public async Task<IHttpActionResult> Register(RegisterBindingModel model)
- {
- Dictionary<string, string> dict = new Dictionary<string, string>();
- if (!ModelState.IsValid)
- {
- return BadRequest(ModelState);
- }
-
- var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
-
- IdentityResult result = await UserManager.CreateAsync(user, model.Password);
-
- if (!result.Succeeded)
- {
- return GetErrorResult(result);
- }
- else
- {
- var showmessage = "User Register Successfully.";
-
- dict.Add("Message", showmessage);
- }
-
- return Ok(dict);
- }
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.
- using System.Security.Claims;
- using System.Threading.Tasks;
- using Microsoft.AspNet.Identity;
- using Microsoft.AspNet.Identity.EntityFramework;
- using Microsoft.AspNet.Identity.Owin;
-
- namespace CFmigration.Models
- {
-
- public class ApplicationUser : IdentityUser
- {
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
- {
-
-
- var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
-
- return userIdentity;
- }
- }
-
- public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
- {
- public ApplicationDbContext()
- : base("DefaultConnection", throwIfV1Schema: false)
- {
- }
-
- public static ApplicationDbContext Create()
- {
- return new ApplicationDbContext();
- }
- }
- }
And, if you will go to the peek definition of Identity User, you will find this.
- namespace Microsoft.AspNet.Identity.EntityFramework
- {
-
-
-
-
-
-
-
-
-
-
-
-
- public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
- where TLogin : IdentityUserLogin<TKey>
- where TRole : IdentityUserRole<TKey>
- where TClaim : IdentityUserClaim<TKey>
- {
-
-
-
- public IdentityUser();
-
-
-
-
- public virtual string Email { get; set; }
-
-
-
- public virtual bool EmailConfirmed { get; set; }
-
-
-
- public virtual string PasswordHash { get; set; }
-
-
-
-
- public virtual string SecurityStamp { get; set; }
-
-
-
- public virtual string PhoneNumber { get; set; }
-
-
-
- public virtual bool PhoneNumberConfirmed { get; set; }
-
-
-
- public virtual bool TwoFactorEnabled { get; set; }
-
-
-
-
- public virtual DateTime? LockoutEndDateUtc { get; set; }
-
-
-
- public virtual bool LockoutEnabled { get; set; }
-
-
-
- public virtual int AccessFailedCount { get; set; }
-
-
-
- public virtual ICollection<TRole> Roles { get; }
-
-
-
- public virtual ICollection<TClaim> Claims { get; }
-
-
-
- public virtual ICollection<TLogin> Logins { get; }
-
-
-
- public virtual TKey Id { get; set; }
-
-
-
- public virtual string UserName { get; set; }
- }
- }
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.
- using System.Security.Claims;
- using System.Threading.Tasks;
- using Microsoft.AspNet.Identity;
- using Microsoft.AspNet.Identity.EntityFramework;
- using Microsoft.AspNet.Identity.Owin;
-
- namespace CFmigration.Models
- {
-
- public class ApplicationUser : IdentityUser
- {
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
- {
-
-
- var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
-
- return userIdentity;
- }
- }
-
- public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
- {
- public ApplicationDbContext()
- : base("DefaultConnection", throwIfV1Schema: false)
- {
- }
-
- public static ApplicationDbContext Create()
- {
- return new ApplicationDbContext();
- }
- }
- }
Now, for saving these newly changed data in DB, please modify the Registration method.
-
- [AllowAnonymous]
- [Route("Register")]
- public async Task<IHttpActionResult> Register(RegisterBindingModel model)
- {
- Dictionary<string, string> dict = new Dictionary<string, string>();
- if (!ModelState.IsValid)
- {
- return BadRequest(ModelState);
- }
-
- var user = new ApplicationUser() { UserName = model.Email, Email = model.Email,FirstName=model.FirstName,LastName=model.LastName };
-
- IdentityResult result = await UserManager.CreateAsync(user, model.Password);
-
- if (!result.Succeeded)
- {
- return GetErrorResult(result);
- }
- else
- {
- var showmessage = "User Register Successfully.";
-
- dict.Add("Message", showmessage);
- }
-
- return Ok(dict);
- }
Now, all our Models have changed. For enabling migration, we should follow the below three steps.
- Enable-Migrations
- Add-Migration <name>
- 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.