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

Santosh

2016/05/01

Categories: Programming Tags: asp.net 5 mvc 5

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.

Screenshot shows user email

The solution which I used includes four steps:

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);
}

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);
}

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;
        }
    }
}

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.