Reading and writing custom ASP.NET Core Identity user properties

A bit more on using ASP.NET Core Identity, this time reading and writing custom properties of the User

Adding a custom property to users that're accessed via ASP.NET Core Identity is ultimately a fairly simple exercise; extend the IdentityUser type with a custom one, fix up all the places that refer explicitly to IdentityUser, add the property to the custom type and make sure there's a database migration in place. What's also important is to make sure it actually works! Manipulating the property during the registration process, e.g. to show a field that the user can populate, isn't something I'll need to do as the final project won't provide self-service registration. If it is something you need to do, it looks like scaffolding Identity in ASP.NET Core projects (from is probably a good place to start. 

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
  4. Reading and writing custom ASP.NET Core Identity user properties (this post)
  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

Getting the ApplicationIdentityUser

I'm going to use a lazy approach to retrieve the EmployeeId property, punching a hole into the boilerplate for the Index view on the Home controller that comes in the default template application to display it. In order to do that we need an instance of the ASP.NET Core Identity UserManager available in the controller so the very first thing to do is set that up so .NET Core can inject that via the constructor:

public UserManager<ApplicationIdentityUser> UserManager { get; set; }

public HomeController(UserManager<ApplicationIdentityUser> userManager)
    UserManager = userManager;

Once that's in place, next up we want to use the GetUserAsync method to retrieve an instance of ApplicationIdentityUser for the currently logged in user. This means making the controller method asynchronous so that we can await the call to GetUserAsync (Remember: Never force the hand of async code by retrieving the .Result property of the returned Task<T>, bad things can and will happen):

public async Task<IActionResult> Index()
    return View();

Again, not a lot of code change required and at this point Visual Studio will complain that:

Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

So let's give it what it wants...

var applicationUser = await UserManager.GetUserAsync(User);
if (applicationUser != null)
    ViewData["EmployeeId"] = applicationUser.EmployeeId.HasValue ? applicationUser.EmployeeId.Value : -1;
    ViewData["EmployeeId"] = "No User";

With that code in place, and a small tweak to the view to present the value that's been stored in ViewData:

<div class="col-md-3">
    <h2>The current user has an employee id of:</h2>

This is what can be seen for a logged in user, it's not particularly attractive but it proves the code's doing as intended:

An ugly little bit if UI wedged into the default ASP.NET Core MVC template that shows the fact that we're getting the custom data value from the EmployeeId property

Updating the ApplicationIdentityUser

Now that we've got code that's merrily retrieving the ApplicationIdentityUser a bit of code that modifies the value and persists it back to the database is needed. Again I'm going to go for a lazy option here and choose to add a bit of hard-coded logic to a controler action to change the value. This time I'm going to add it to the About action, again on the Home controller. After making the action async in the same way as I did for the Index action, I added this code:

var applicationUser = await UserManager.GetUserAsync(User);
if (applicationUser != null)
    applicationUser.EmployeeId = applicationUser.EmployeeId.HasValue
        ? applicationUser.EmployeeId.Value + 1 : 0;

    var result = await UserManager.UpdateAsync(applicationUser);

With that in place, it should mean that every visit to the applications About page causes the logged in users EmployeeId to increment by one, not exactly what an employee id is generally supposed to do but it does show using the ASP.NET Core Identity UserManager to retrieve, modify and then persist changes back to the underlying datastore. And here we have it, after a couple of visits to the About page, the app homepage is showing the users EmployeeId duly incremented:

The homepage showing the Employee Id value having been incremented to 2 (from null) by three visits to the About page

You could, if you wanted, poke around directly in the database by injecting an instance of ApplicationDbContext (the EF context that ASP.NET Core Identity is using for loading/saving user data) into the controller, pull data from it and manipulate it, with something like this being a starting point:

var userFromDbContext = DbContext.Users.Where(u => u.UserName == User.Identity.Name).First();

And here's the data that retrieves:

Retrieving user data directly from the Entity Framework DbContext that sits underneath ASP.NET Core Identity. Please, don't do that!

But that then ties you irrevocably to the Entity Framework backed identity store, along with tying you to the schema behind it. Please, don't do that. Stick to accessing and manipulating user data via the UserManager API, that way if you want to swap out the unerlying storage mechanism at a later date, you'll be able to do so with hopefully the minimum of fuss. 

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