{"id":2300,"date":"2026-07-20T12:41:37","date_gmt":"2026-07-20T10:41:37","guid":{"rendered":"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-10\/"},"modified":"2026-08-26T21:04:15","modified_gmt":"2026-08-26T19:04:15","slug":"build-a-complete-app-with-asp-net-c-sql-lite-part-10","status":"publish","type":"post","link":"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-10\/","title":{"rendered":"Build a Complete App with ASP.Net, C#, SQL Lite \u2013 Part 10"},"content":{"rendered":"<p><!-- ktg-updated-banner --><\/p>\n<p><em>Updated August 2026 \u2014 Part 10 restored (user profile in the header + dropdown Name fix).<\/em><\/p>\n<p>In this part we finish the Identity work from Part 9: show the <strong>logged-in user<\/strong> in the header, and provide links to <strong>profile<\/strong> and <strong>logout<\/strong>. Before that, we fix a small UX bug \u2014 Country (and similar) dropdowns that show IDs instead of names.<\/p>\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-part-1\/\">Part 1<\/a> \u00b7<br \/>\n<a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-2\/\">Part 2<\/a> \u00b7<br \/>\n<a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-3\/\">Part 3<\/a> \u00b7<br \/>\n<a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-4\/\">Part 4<\/a><\/li>\n<li><a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-5\/\">Part 5<\/a> \u00b7<br \/>\n<a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-6\/\">Part 6<\/a> \u00b7<br \/>\n<a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-7\/\">Part 7<\/a> \u00b7<br \/>\n<a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-8\/\">Part 8<\/a> \u00b7<br \/>\n<a href=\"https:\/\/kindsonthegenius.com\/blog\/build-a-complete-app-with-asp-net-c-sql-lite-part-9\/\">Part 9 (registration &amp; login)<\/a><\/li>\n<\/ul>\n<p>We will cover:<\/p>\n<ol>\n<li><a href=\"#t1\">Show Name instead of Id in SelectLists<\/a><\/li>\n<li><a href=\"#t2\">Pass the current user into the layout<\/a><\/li>\n<li><a href=\"#t3\">Header UI \u2013 greeting, profile, logout<\/a><\/li>\n<li><a href=\"#t4\">Optional Profile page (FirstName \/ LastName)<\/a><\/li>\n<li><a href=\"#t5\">Quick test checklist<\/a><\/li>\n<\/ol>\n<p><strong id=\"t1\">1. Show Name instead of Id in SelectLists<\/strong><\/p>\n<p>On <strong>New Patient<\/strong>, the Country dropdown may list country IDs instead of country names. That happens when <code>SelectList<\/code> uses the wrong display property.<\/p>\n<p><strong>Step 1:<\/strong> Open <code>PatientController.cs<\/code> and find where you build the Country list (Create\/Edit GET actions). It often looks like:<\/p>\n<pre><code>ViewData[\"CountryId\"] = new SelectList(_context.Countries, \"Id\", \"Id\");\n<\/code><\/pre>\n<p><strong>Step 2:<\/strong> Change the third argument from <code>\"Id\"<\/code> to <code>\"Name\"<\/code> (the property on your <code>Country<\/code> model that holds the display text):<\/p>\n<pre><code>ViewData[\"CountryId\"] = new SelectList(_context.Countries, \"Id\", \"Name\");\n<\/code><\/pre>\n<p>Do the same in Edit if you pass a selected value:<\/p>\n<pre><code>ViewData[\"CountryId\"] = new SelectList(_context.Countries, \"Id\", \"Name\", patient.CountryId);\n<\/code><\/pre>\n<p><strong>Step 3:<\/strong> In <code>Views\/Patient\/Create.cshtml<\/code> (and Edit), the dropdown should bind to <code>CountryId<\/code> as the value, while the list text comes from <code>Name<\/code>:<\/p>\n<pre><code>&lt;select asp-for=\"CountryId\" class=\"form-control\"\n        asp-items=\"ViewBag.CountryId\"&gt;&lt;\/select&gt;\n<\/code><\/pre>\n<p>Repeat for any other FK dropdowns (State, City, \u2026) that currently show IDs.<\/p>\n<p><strong id=\"t2\">2. Pass the current user into the layout<\/strong><\/p>\n<p>Part 9 added <code>FirstName<\/code> \/ <code>LastName<\/code> on <code>ApplicationUser<\/code>. The layout needs that data for every page.<\/p>\n<p><strong>Option A \u2013 inject <code>UserManager<\/code> in <code>_Layout.cshtml<\/code> (simple for this series):<\/strong><\/p>\n<pre><code>@using Microsoft.AspNetCore.Identity\n@using YourApp.Data\n@inject SignInManager&lt;ApplicationUser&gt; SignInManager\n@inject UserManager&lt;ApplicationUser&gt; UserManager\n<\/code><\/pre>\n<p>Then, inside the header markup:<\/p>\n<pre><code>@if (SignInManager.IsSignedIn(User))\n{\n    var appUser = await UserManager.GetUserAsync(User);\n    var display = appUser?.FirstName ?? appUser?.Email ?? User.Identity?.Name;\n    &lt;!-- use display below --&gt;\n}\n<\/code><\/pre>\n<p>If your layout is not already async, change the top of <code>_Layout.cshtml<\/code> to use an async pattern supported by your ASP.NET Core version, or load the display name in a <strong>ViewComponent<\/strong> (cleaner for larger apps).<\/p>\n<p><strong>Option B \u2013 ViewComponent <code>UserNavViewComponent<\/code>:<\/strong><\/p>\n<pre><code>public class UserNavViewComponent : ViewComponent\n{\n    private readonly UserManager&lt;ApplicationUser&gt; _users;\n    public UserNavViewComponent(UserManager&lt;ApplicationUser&gt; users) =&gt; _users = users;\n\n    public async Task&lt;IViewComponentResult&gt; InvokeAsync()\n    {\n        var user = await _users.GetUserAsync(HttpContext.User);\n        return View(user);\n    }\n}\n<\/code><\/pre>\n<p>Invoke with <code>@await Component.InvokeAsync(\"UserNav\")<\/code>.<\/p>\n<p><strong id=\"t3\">3. Header UI \u2013 greeting, profile, logout<\/strong><\/p>\n<p>In the navbar (right side), replace a static \u201cLogin\u201d with a signed-in menu:<\/p>\n<pre><code>&lt;ul class=\"navbar-nav\"&gt;\n@if (SignInManager.IsSignedIn(User))\n{\n    var appUser = await UserManager.GetUserAsync(User);\n    var display = !string.IsNullOrWhiteSpace(appUser?.FirstName)\n        ? $\"{appUser.FirstName} {appUser.LastName}\".Trim()\n        : appUser?.Email;\n\n    &lt;li class=\"nav-item\"&gt;\n        &lt;span class=\"nav-link\"&gt;Hello, @display&lt;\/span&gt;\n    &lt;\/li&gt;\n    &lt;li class=\"nav-item\"&gt;\n        &lt;a class=\"nav-link\" asp-area=\"Identity\" asp-page=\"\/Account\/Manage\/Index\"&gt;Profile&lt;\/a&gt;\n    &lt;\/li&gt;\n    &lt;li class=\"nav-item\"&gt;\n        &lt;form class=\"form-inline\" asp-area=\"Identity\" asp-page=\"\/Account\/Logout\"\n              asp-route-returnUrl=\"@Url.Action(\"Index\", \"Home\")\" method=\"post\"&gt;\n            &lt;button type=\"submit\" class=\"nav-link btn btn-link\"&gt;Logout&lt;\/button&gt;\n        &lt;\/form&gt;\n    &lt;\/li&gt;\n}\nelse\n{\n    &lt;li class=\"nav-item\"&gt;\n        &lt;a class=\"nav-link\" asp-area=\"Identity\" asp-page=\"\/Account\/Register\"&gt;Register&lt;\/a&gt;\n    &lt;\/li&gt;\n    &lt;li class=\"nav-item\"&gt;\n        &lt;a class=\"nav-link\" asp-area=\"Identity\" asp-page=\"\/Account\/Login\"&gt;Login&lt;\/a&gt;\n    &lt;\/li&gt;\n}\n&lt;\/ul&gt;\n<\/code><\/pre>\n<p>Logout must be a <strong>POST<\/strong> (Identity antiforgery). Do not use a plain GET link for logout.<\/p>\n<p><strong id=\"t4\">4. Optional Profile page (FirstName \/ LastName)<\/strong><\/p>\n<p>Scaffolded Identity already has <strong>Manage<\/strong> under <code>\/Identity\/Account\/Manage<\/code>. To edit FirstName\/LastName:<\/p>\n<p><strong>Step 1:<\/strong> Scaffold Identity pages for <code>Account\/Manage\/Index<\/code> if you have not (Visual Studio \u2192 Add \u2192 New Scaffolded Item \u2192 Identity).<\/p>\n<p><strong>Step 2:<\/strong> Extend the Manage <code>InputModel<\/code>:<\/p>\n<pre><code>[Required]\n[Display(Name = \"First name\")]\npublic string FirstName { get; set; }\n\n[Required]\n[Display(Name = \"Last name\")]\npublic string LastName { get; set; }\n<\/code><\/pre>\n<p><strong>Step 3:<\/strong> On GET, load from <code>ApplicationUser<\/code>; on POST, assign and <code>await _userManager.UpdateAsync(user)<\/code>.<\/p>\n<p><strong>Step 4:<\/strong> Add matching inputs in the Manage Index Razor page (same pattern as Register in Part 9).<\/p>\n<p><strong id=\"t5\">5. Quick test checklist<\/strong><\/p>\n<ol>\n<li>Register a user with FirstName\/LastName (Part 9).<\/li>\n<li>Log in \u2014 header shows <em>Hello, {FirstName}\u2026<\/em>.<\/li>\n<li>Open Profile \u2014 change names; header updates after refresh.<\/li>\n<li>Logout \u2014 returns to login\/home; protected pages redirect to login (<code>[Authorize]<\/code> on Home from Part 9).<\/li>\n<li>New Patient \u2014 Country dropdown shows names, saves correct <code>CountryId<\/code>.<\/li>\n<\/ol>\n<p><strong>Next steps<\/strong><\/p>\n<p>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 <code>[Authorize(Roles = \"...\")]<\/code>. Keep building on the same SQLite + Identity setup from Parts 4 and 9.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Updated August 2026 \u2014 Part 10 restored (user profile in the header + dropdown Name fix). In this part we finish the Identity work from &hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[35],"tags":[],"class_list":["post-2300","post","type-post","status-publish","format-standard","hentry","category-algorithms"],"acf":[],"_links":{"self":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2300","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/comments?post=2300"}],"version-history":[{"count":2,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2300\/revisions"}],"predecessor-version":[{"id":2444,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2300\/revisions\/2444"}],"wp:attachment":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/media?parent=2300"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/categories?post=2300"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/tags?post=2300"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}