Search code examples
c#asp.net-coreentity-framework-coreasp.net-identityblazor-server-side

Blazor Server with AspNetCore.Identity.EntityFrameworkCore 7 Extended IdentityUser


I'm learning Blazor and need some help.

My Blazor Server project requires an extended IdentityUser.

I would like to access the FirstName property in the LoginDisplay.razor file which is shown below.

Most of the discussions I have found are too old or do not address my specific issue.

MyProjectUser

using Microsoft.AspNetCore.Identity;

namespace MyProject.Data;

public class MyProjectUser : IdentityUser
{
    [PersonalData]
    public string? FirstName { get; set; }

    [PersonalData]
    public string? LastName { get; set; }
}

MyProjectContext

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace MyProject.Data;

public class MyProjectContext : IdentityDbContext<MyProjectUser>
{
    public MyProjectContext(DbContextOptions<MyProjectContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
    }
}

MyProject's Program.cs

using MyProject.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Components.Authorization;
using MyProject.Areas.Identity;

namespace MyProject
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            var connectionString = builder.Configuration.GetConnectionString("MyProjectContext") ?? throw new InvalidOperationException("Connection string 'MyProjectContext' not found.");

            builder.Services.AddDbContext<MyProjectContext>(options => options.UseSqlServer(connectionString));

            builder.Services.AddDefaultIdentity<MyProjectUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<MyProjectContext>();

            // Add services to the container.
            builder.Services.AddRazorPages();
            builder.Services.AddServerSideBlazor();

            builder.Services.AddHttpContextAccessor();

            builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<MyProjectUser>>();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (!app.Environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseRouting();
            app.UseAuthorization();

            app.MapBlazorHub();
            app.MapFallbackToPage("/_Host");

            app.Run();
        }
    }
}

Everything works great, database is updated etc.

I simply want to access the MyProjectUser's FirstName property here:

LoginDisplay.razor

<CascadingAuthenticationState>
    <AuthorizeView>
        <Authorized>
            <a href="Identity/Account/Manage">Hello, -->@context.User.Identity?.Name!</a>
            <form method="post" action="Identity/Account/Logout">
                <button type="submit" class="nav-link btn btn-link">Log out</button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a href="Identity/Account/Register">Register</a>
            <a href="Identity/Account/Login">Log in</a>
        </NotAuthorized>
    </AuthorizeView>
</CascadingAuthenticationState>

The LoginDisplay is used in MainLayout.razor

@using Microsoft.AspNetCore.Identity;
@using MyProject.Data;

@inherits LayoutComponentBase

@inject UserManager<MyProjectUser> UserManager;
@inject AuthenticationStateProvider GetAuthenticationStateAsync

<PageTitle>MyProject</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>      
        <div class="top-row px-4">
            <LoginDisplay />
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            @Body
        </article>
    </main>
</div>

Any help is greatly appreciated.


Solution

  • We need to add custom properities in MyProjectUser class, and run below command.

    PM> Add-Migration FirstName  -Context 'MyProjectContext'
    PM> Update-Database  -Context 'MyProjectContext'
    

    Then I navigate to the Data in DB, add my FirstName and LastName.

    enter image description here

    My Test Result

    enter image description here

    My LoginDisplay.razor

    @using blazorfirstname.Areas.Identity.Data
    @using Microsoft.AspNetCore.Identity
    @inject UserManager<MyProjectUser> userManager
    @inject AuthenticationStateProvider authenticationStateProvider
    
    <AuthorizeView>
        <Authorized>
            <a href="Identity/Account/Manage">Hello, @GetFirstNameAsync() !</a>
            <form method="post" action="Identity/Account/Logout">
                <button type="submit" class="nav-link btn btn-link">Log out</button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a href="Identity/Account/Register">Register</a>
            <a href="Identity/Account/Login">Log in</a>
        </NotAuthorized>
    </AuthorizeView>
    
    
    @code {
        private string firstName;
    
        protected override async Task OnInitializedAsync()
        {
            var authenticationState = await authenticationStateProvider.GetAuthenticationStateAsync();
            var user = await userManager.GetUserAsync(authenticationState.User);
            firstName = user?.FirstName;
        }
    
        private string GetFirstNameAsync()
        {
            return firstName ?? string.Empty;
        }
    }
    

    My MyProjectUser.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Identity;
    
    namespace blazorfirstname.Areas.Identity.Data;
    
    // Add profile data for application users by adding properties to the MyProjectUser class
    public class MyProjectUser : IdentityUser
    {
        [PersonalData]
        public string? FirstName { get; set; }
        [PersonalData]
        public string? LastName { get; set; }
    }