Updated August 2026 — Part 10 restored (user profile in the header + dropdown Name fix).
In this part we finish the Identity work from Part 9: show the logged-in user in the header, and provide links to profile and logout. Before that, we fix a small UX bug — Country (and similar) dropdowns that show IDs instead of names.
Previously:
We will cover:
- Show Name instead of Id in SelectLists
- Pass the current user into the layout
- Header UI – greeting, profile, logout
- Optional Profile page (FirstName / LastName)
- Quick test checklist
1. Show Name instead of Id in SelectLists
On New Patient, the Country dropdown may list country IDs instead of country names. That happens when SelectList uses the wrong display property.
Step 1: Open PatientController.cs and find where you build the Country list (Create/Edit GET actions). It often looks like:
ViewData["CountryId"] = new SelectList(_context.Countries, "Id", "Id");
Step 2: Change the third argument from "Id" to "Name" (the property on your Country model that holds the display text):
ViewData["CountryId"] = new SelectList(_context.Countries, "Id", "Name");
Do the same in Edit if you pass a selected value:
ViewData["CountryId"] = new SelectList(_context.Countries, "Id", "Name", patient.CountryId);
Step 3: In Views/Patient/Create.cshtml (and Edit), the dropdown should bind to CountryId as the value, while the list text comes from Name:
<select asp-for="CountryId" class="form-control"
asp-items="ViewBag.CountryId"></select>
Repeat for any other FK dropdowns (State, City, …) that currently show IDs.
2. Pass the current user into the layout
Part 9 added FirstName / LastName on ApplicationUser. The layout needs that data for every page.
Option A – inject UserManager in _Layout.cshtml (simple for this series):
@using Microsoft.AspNetCore.Identity
@using YourApp.Data
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
Then, inside the header markup:
@if (SignInManager.IsSignedIn(User))
{
var appUser = await UserManager.GetUserAsync(User);
var display = appUser?.FirstName ?? appUser?.Email ?? User.Identity?.Name;
<!-- use display below -->
}
If your layout is not already async, change the top of _Layout.cshtml to use an async pattern supported by your ASP.NET Core version, or load the display name in a ViewComponent (cleaner for larger apps).
Option B – ViewComponent UserNavViewComponent:
public class UserNavViewComponent : ViewComponent
{
private readonly UserManager<ApplicationUser> _users;
public UserNavViewComponent(UserManager<ApplicationUser> users) => _users = users;
public async Task<IViewComponentResult> InvokeAsync()
{
var user = await _users.GetUserAsync(HttpContext.User);
return View(user);
}
}
Invoke with @await Component.InvokeAsync("UserNav").
3. Header UI – greeting, profile, logout
In the navbar (right side), replace a static “Login” with a signed-in menu:
<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
var appUser = await UserManager.GetUserAsync(User);
var display = !string.IsNullOrWhiteSpace(appUser?.FirstName)
? $"{appUser.FirstName} {appUser.LastName}".Trim()
: appUser?.Email;
<li class="nav-item">
<span class="nav-link">Hello, @display</span>
</li>
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Manage/Index">Profile</a>
</li>
<li class="nav-item">
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout"
asp-route-returnUrl="@Url.Action("Index", "Home")" method="post">
<button type="submit" class="nav-link btn btn-link">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Login">Login</a>
</li>
}
</ul>
Logout must be a POST (Identity antiforgery). Do not use a plain GET link for logout.
4. Optional Profile page (FirstName / LastName)
Scaffolded Identity already has Manage under /Identity/Account/Manage. To edit FirstName/LastName:
Step 1: Scaffold Identity pages for Account/Manage/Index if you have not (Visual Studio → Add → New Scaffolded Item → Identity).
Step 2: Extend the Manage InputModel:
[Required]
[Display(Name = "First name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last name")]
public string LastName { get; set; }
Step 3: On GET, load from ApplicationUser; on POST, assign and await _userManager.UpdateAsync(user).
Step 4: Add matching inputs in the Manage Index Razor page (same pattern as Register in Part 9).
5. Quick test checklist
- Register a user with FirstName/LastName (Part 9).
- Log in — header shows Hello, {FirstName}….
- Open Profile — change names; header updates after refresh.
- Logout — returns to login/home; protected pages redirect to login (
[Authorize]on Home from Part 9). - New Patient — Country dropdown shows names, saves correct
CountryId.
Next steps
You now have a usable Identity shell on the hospital app. Natural follow-ons: roles (Admin vs Staff), seed data for countries, and locking down Patient/CRUD actions with [Authorize(Roles = "...")]. Keep building on the same SQLite + Identity setup from Parts 4 and 9.