Extending the ASP.NET Core Identity user

Using Entity Framework migrations to add new properties to ASP.NET Core identity users

In two recent posts I've been looking at ASP.NET Core Identity, first changing it up so that the data-type for the Id fields in Integer rather than a stringified GUID and then separating out the code that talks to ASP.NET Identity into a separate library to make it easier to share between multiple web applications that'll be using the same identity database. Next up is actually customising the identity user a little more to add some business specific data-points that're above and beyond those stored by ASP.NET Core Identity by default.

Related posts:

  1. Taking the GUID out of ASP.NET Core Identity
  2. Splitting out ASP.NET Core Identity into a separate library
  3. Extending the ASP.NET Core Identity user (this post)
  4. Reading and writing custom ASP.NET Core Identity user properties
  5. Extending the ASP.NET Core Identity UserManager to set the Employee Id during registration
  6. The finishing touches to hooking into ASP.NET Core Identity user creation

Adding an Employee Id

The hypothetical web application suite I'm building is intended to be a HR system, so something that'll allow users to book holiday, approve holiday for their reports, and all the other stuff that an HR portal allows you to do. In order to book holiday the system will need to know which employee you are, which means associating a login with an employee. There are already a couple of values that're stored by Identity that we could potentially use, such as the Id or the Email Address that are on record. This would mean storing a value from the identity database (i.e. from the AspNetUsers table) in the business database (i.e. against the Employee table). Email address is out as this is mutable for a given person (marriage, anyone?) and having a key data-point like this which can change is a bit of a no-no, Id is certainly a candidate though.

Even though the Id column from the AspNetUsers table is an option, it doesn't sit well with me that this be added to the Employee table in the "business" database as this would mean that the application would need to be able to read/access the Identity data-store to associate a user with an employee. Instead I'm going to store the employee id from the application inside the Identity store by adding a property/column to it.

The simplest way to do this is to add a new property to the ApplicationUser class, which will then look a little like this:

public class ApplicationIdentityUser : IdentityUser
{
    public int? EmployeeId { get; set; }
}

Once that's done it's a matter of creating a migration so that Entity Framework Core can take care of updating the database schema for me. As in the previous article, this means running the command:

dotnet ef migrations add EmployeeIdAdded -o Data\Migrations

From the projects directory. Unfortunately, this is where a small snag is hit, after a bit of thinking this error pops out:

Startup project 'RW.HumanResourcesPortal.Identity.csproj' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the Entity Framework Core .NET Command-line Tools with this project, add an executable project targeting .NET Core or .NET Framework that references this project, and set it as the startup project using --startup-project; or, update this project to cross-target .NET Core or .NET Framework.

According to this post on Stack Overflow, one way of solving this is to add a project to the solution that targets a specific runtime (e.g. .NET Core) rather than .NET Standard, which is what the project currently targets. A bit more digging pulls up an issue in the Entity Framework Core GitHub repository which reiterates that the solution is to either change the target framework, or use a helper project that targets a real runtime. I'm going to chose the latter. In this instance I'm going to use the RW.HumanResources.Web project, as I've yet to split the library and web app out into separate repositories. So the command becomes:

dotnet ef migrations add EmployeeIdAdded -o Data\Migrations --startup-project ..\RW.HumanResourcesPortal.Web

This results in a couple of new files in the Data\Migrations folder for the EmployeeAdded migration, the main one containing the migration code for adding the new column (or removing it if the model is downgraded):

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn(
        name: "EmployeeId",
        table: "AspNetUsers",
        nullable: true);
}

protected override void Down(MigrationBuilder migrationBuilder)
{
    migrationBuilder.DropColumn(
        name: "EmployeeId",
        table: "AspNetUsers");
}

Success, so now to run the web application and get the migration done.

Applying the migration

As with when I created a migration to change the Id column from a GUID to an Integer, running the web application and doing something that triggers Entity Framework (logging in!) prompts me to migrate the database:

Again Entity Framework has piped up to point out that there's a migration that needs to be carried out

Just for variety I'm going to stop debugging and run the dotnet ef database update command from the command line to see if that's going to work, or whether it'll need the --startup-project parameter specifying. From reading the GitHub issue where it's explained that the need for a real framework is because Entity Framework Core is actually running code, not just generating it, it's likely that adding the parameter will be required. 

Running the plain command results in the same error as was seen when creating the migration, but adding the -s parameter (running dotnet ef database update --help lists this as a short-form of the parameter name) generates quite a few lines of output, the key ones being near the middle:

Applying migration '20181010161548_EmployeeIdAdded'.
info: Microsoft.EntityFrameworkCore.Migrations[20402]
      Applying migration '20181010161548_EmployeeIdAdded'.

Looking at the database there's the newly added EmployeeId column at the far right:

A snippet of the AspNetUsers table shown in SQL Server Management Studio with the newly added EmployeeId column visible

So that's all done and working. The only thing I haven't verified is that the EmployeeId property is read/written from and to the database correctly, but I'll leave that for another (shorter!) post.

About Rob

I've been interested in computing since the day my Dad purchased his first business PC (an Amstrad PC 1640 for anyone interested) which introduced me to MS-DOS batch programming and BASIC.

My skillset has matured somewhat since then, which you'll probably see from the posts here. You can read a bit more about me on the about page of the site, or check out some of the other posts on my areas of interest.

No Comments

Add a Comment