Display full user name instead of email in asp.net 5 MVC 6

Are you also starting your web development journey with ASP.Net 5? I think, as this point of time most of the resources are addressing the problems in ASP.net 4.6. Most of the questions are asked for this version. In my view, that is pretty logical. If you ask me why, I would say the ASP.net 4.6 is proven and tested solution at this point of time and ASP.net 5 is still in its RC1 phase. It is production supported by still a lot is missing.

I also started my journey with MVC 6 some time back with a production grade website development. And lot of questions popped up in the journey. In this series of blogs, I will document most of my findings over few coming weeks.

This is first question in the series. How do you display user’s full name (Or may be first name) in place of the email (which is as it comes from default templates)? You can refer the below image to see how does it appear with the default template.

Screen Shot  Shows User Email
Screen Shot Shows User Email

The solution which I used includes four steps:

1. Add fields for FirstName and LastName to your ApplicationUser Model and update your templates to reflect it.

Add the required fields to ApplicationUser.cs

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Next Update the view model for register view (RegisterViewModel.cs) as following:

public class RegisterViewModel
{
    [Required]
    [EmailAddress]
    [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; }
       
    [Required]
    [DisplayAttribute(Name = "First Name")]
    public string FirstName { get; set; }
       
    [Required]
    [DisplayAttribute(Name = "Last Name")]
    public string LastName { get; set; }
}

Build the project and create and apply migrations to update the database.

dnx ef migrations add FirstNameLastNameAdded
dnx ef database update

Update the Register.cshtml file to add input fields for FirstName and LastName. And finally update the Register Post action in Account controller.

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        //Below line is updated to add FirstName and LastName fields to DB
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email, FirstName = model.FirstName, LastName = model.LastName };
        var result = await _userManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            await _signInManager.SignInAsync(user, isPersistent: false);
            _logger.LogInformation(3, "User created a new account with password.");
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }
        AddErrors(result);
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

2. Update your sign up functions to add user claims for first name and last name. Adding the FirstName and Last name fields to Claim principal avoids hitting database everytime user refreshes the page. To add claims for user, we will again update the Register action in the AccountController.

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        //Below line is updated to add FirstName and LastName fields to DB
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email, FirstName = model.FirstName, LastName = model.LastName };
        var result = await _userManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            await _signInManager.SignInAsync(user, isPersistent: false);
            _logger.LogInformation(3, "User created a new account with password.");

            // Add User Claims for full name. You can check for the success of addition
            await _userManager.AddClaimAsync(user, new Claim("FirstName", user.FirstName));
            await _userManager.AddClaimAsync(user, new Claim("LastName", user.LastName));

            return RedirectToAction(nameof(HomeController.Index), "Home");
        }
        AddErrors(result);
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

3. Write extension method for ClaimPrincipal for retrieving the data from User Claims. Now we need to create few extension functions for ClaimPrincipal. Add a new file called ClaimsPrincipalExtension.cs to your project and add following code to it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace UserNameDemo.Extensions
{
    public static class ClaimsPrincipalExtension
    {
        public static string GetFirstName(this ClaimsPrincipal principal)
        {
            var firstName = principal.Claims.FirstOrDefault(c => c.Type == "FirstName");
            return firstName?.Value;
        }

        public static string GetLastName(this ClaimsPrincipal principal)
        {
            var lastName = principal.Claims.FirstOrDefault(c => c.Type == "LastName");
            return lastName?.Value;
        }
    }
}

4. Use the extension function in your _LoginPartial.cshtml file. Now, we can use these extension function in _LoginPartial to get the first name and last name. Here is content my update file.

@using System.Security.Claims
@using UserNameDemo.Extensions
@if (User.IsSignedIn())
{
    <form asp-controller="Account" asp-action="LogOff" method="post" id="logoutForm" class="navbar-right">
        <ul class="nav navbar-nav navbar-right">
            <li>
                <a asp-controller="Manage" asp-action="Index" title="Manage">Hello @User.GetFirstName() @User.GetLastName()!</a>
            </li>
            <li>
                <button type="submit" class="btn btn-link navbar-btn navbar-link">Log off</button>
            </li>
        </ul>
    </form>
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li><a asp-controller="Account" asp-action="Register">Register</a></li>
        <li><a asp-controller="Account" asp-action="Login">Log in</a></li>
    </ul>
}

And that is it. Please let me know if this worked for you or you feel this is not an optimal solution and should be improved upon.

  • Nyron Burke

    @using should include @using UserNameDemo.Extensions

  • gsforlife

    error cannot convert applicationUser to string in the registration claim
    await _userManager.AddClaimAsync(user, new Claim(“FirstName”, user.FirstName));
    await _userManager.AddClaimAsync(user, new Claim(“LastName”, user.LastName));

    • Few quick questions:
      1. What version of EF and Identity are you using?
      2. For which argument are you getting this issue? The string arguments are only passed to Claim constructor. There first argument is a string there and second is also string as per my code.

  • thevlf

    I can’t get my Claim to persist — I can see it in the AccountController code (i verify after the AddClaimAsync call) — but when ClaimsPrincipalExtension code is called – the principal does not have the claim

    • Dhananjay Vasa

      Try clearing your cookies. CTRL+SHIFT+DELETE. I had the same problem but this worked for me.

      • thevlf

        I think that may have been it – the code eventually worked (I made not changes to it). Thanks!!

  • Dhananjay Vasa

    Think there’s a typo here:
    var lastName = principal.Claims.FirstOrDefault(c => c.Type == “FirstName”);
    should be
    var lastName = principal.Claims.FirstOrDefault(c => c.Type == “LastName”);

  • Giulio Fronterotta

    Hi Santosh !
    Nice article, this is the solution I was looking for 2 days !!! 🙂
    Only 1 thing. Everything is fine but the properties are not shown during first Register redirect. If you log out and in, it works !

    • Thaks Giulio. Glad that it helped you.

    • Felix

      In the Register action, move the code adding claims to be above the signInManager.SignInAsync code

  • BrianR

    Is there any chance of seeing the entire working solution for the above in a zip?
    There is very little in the way of working examples for this type of claim that fits into default MVC code- aside from an example thatI found on Dino Espositos site.

    • I will create a working solution and put it on GitHub.