Installing MudBlazor

dotnet new blazor -o DnsMan --auth Individual
cd DnsMan
dotnet add package Pomelo.EntityFrameworkCore.MySql --version 9.0.*
dotnet add package Microsoft.EntityFrameworkCore.Design --version 9.0.*
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore --version 9.0.*
dotnet add package MudBlazor

MariaDb Connection string

Server=192.168.1.154;Port=3306;Database=DnsMan;User=user;Password=password;

Program.cs

remove

	app.UseAntiforgery();
	
	builder.Services.AddDbContext<ApplicationDbContext>(options =>
	options.UseSqlite(connectionString));

Add

using Pomelo.EntityFrameworkCore.MySql.Infrastructure;

	builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(
		builder.Configuration.GetConnectionString("DefaultConnection"),
		ServerVersion.AutoDetect(
			builder.Configuration.GetConnectionString("DefaultConnection")
		)
	));

Create SeedData.cs

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace DnsMan.Data;

public static class SeedData
{
    public static async Task Initialize(IServiceProvider serviceProvider)
    {
        using var scope = serviceProvider.CreateScope();

        var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
        var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();

        // Ensure DB exists
        await context.Database.MigrateAsync();

        // ---- Roles ----
        const string adminRole = "Admin";

        if (!await roleManager.RoleExistsAsync(adminRole))
        {
            await roleManager.CreateAsync(new IdentityRole(adminRole));
        }

        // ---- Admin User ----
        const string adminEmail = "admin@dnsman.local";
        const string adminPassword = "Admin123!"; // change in production

        var adminUser = await userManager.FindByEmailAsync(adminEmail);

        if (adminUser == null)
        {
            adminUser = new ApplicationUser
            {
                UserName = adminEmail,
                Email = adminEmail,
                EmailConfirmed = true
            };

            var result = await userManager.CreateAsync(adminUser, adminPassword);
            if (!result.Succeeded)
            {
                throw new Exception(
                    "Failed to create admin user: " +
                    string.Join(", ", result.Errors.Select(e => e.Description)));
            }
        }

        if (!await userManager.IsInRoleAsync(adminUser, adminRole))
        {
            await userManager.AddToRoleAsync(adminUser, adminRole);
        }

        // ---- Dummy User ----
        const string userEmail = "user@dnsman.local";
        const string userPassword = "User123!";

        var dummyUser = await userManager.FindByEmailAsync(userEmail);
        if (dummyUser == null)
        {
            dummyUser = new ApplicationUser
            {
                UserName = userEmail,
                Email = userEmail,
                EmailConfirmed = true
            };

            await userManager.CreateAsync(dummyUser, userPassword);
        }
    }
}

Add this to the bottom (just beforeapp.Run();

// Apply migrations and seed database
using (var scope = app.Services.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
    db.Database.Migrate(); // ensure tables exist
    await SeedData.Initialize(scope.ServiceProvider);
}

app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery(); // <- required
app.UseRouting();

Change in Program.cs

builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddSignInManager()
    .AddDefaultTokenProviders();

to

builder.Services.AddIdentityCore<ApplicationUser>(options =>
        options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()                // 👈 THIS LINE
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddSignInManager()
    .AddDefaultTokenProviders();

Check here in Program.cs that all this is set

app.UseHttpsRedirection();

app.MapStaticAssets();

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery(); // <- required

app.MapRazorComponents<App>()

Add to _Imports.razor

@using MudBlazor

Add to Program.cs

using MudBlazor.Services;

builder.Services.AddMudServices();

Replace App.razor

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="@Assets["app.css"]" />
    <link rel="stylesheet" href="@Assets["DnsMan.styles.css"]" />
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
    <link href="@Assets["_content/MudBlazor/MudBlazor.min.css"]" rel="stylesheet" />
    <ImportMap />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet />
</head>

<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
    <script src="@Assets["_content/MudBlazor/MudBlazor.min.js"]"></script>
</body>

</html>

Improved MainLayout.razor

@inherits LayoutComponentBase

@* Required *@
<MudThemeProvider />
<MudPopoverProvider />

@* Needed for dialogs *@
<MudDialogProvider />

@* Needed for snackbars *@
<MudSnackbarProvider />

<MudPaper Class="layout-container">

    <!-- Header (full width) -->
    <MudPaper Class="header" Elevation="0">
        <MudText Typo="Typo.h6">Header Section</MudText>
    </MudPaper>

    <!-- Main content area (3 panels) -->
    <div class="main-content">
        <!-- Left panel -->
        <MudPaper Class="left-panel" Elevation="0">
            <NavMenu />
        </MudPaper>

        <!-- Center panel -->
        <MudPaper Class="center-panel" Elevation="0">
            @Body
        </MudPaper>

        <!-- Right panel -->
        <MudPaper Class="right-panel" Elevation="0">
            <MudText Typo="Typo.body1">Right Panel</MudText>
        </MudPaper>
    </div>

    <!-- Footer (full width) -->
    <MudPaper Class="footer" Elevation="0">
        <MudText Typo="Typo.body2">Footer Section</MudText>
    </MudPaper>

</MudPaper>

<style>
/* Layout container: vertical flex */
.layout-container {
    display: flex;
    flex-direction: column;
    height: 100vh;
}

/* Header: full width */
.header {
    width: 100%;
    background-color: white;
    border-bottom: 2px solid #1976d2;
    padding: 1rem;
}

/* Footer: full width */
.footer {
    width: 100%;
    background-color: white;
    border-top: 2px solid #1976d2;
    padding: 0.5rem;
    margin-top: auto;
}

/* Main content area: horizontal flex, between header and footer */
.main-content {
    display: flex;
    flex: 1; /* fills remaining height */
    overflow: hidden;
}

/* Left panel: fixed width, blue background, border only on right */
.left-panel {
    width: 200px;
    background-color: #1976d2;
    color: white;
    padding: 1rem;
    border-right: 2px solid #1976d2;
}

/* Center panel: fills remaining space, white, border on right */
.center-panel {
    flex: 1;
    background-color: white;
    padding: 1rem;
    border-right: 2px solid #1976d2;
}

/* Right panel: fixed width, white, no right border */
.right-panel {
    width: 200px;
    background-color: white;
    padding: 1rem;
}
</style>

Improved NavMenu.razor

@using MudBlazor
@inherits LayoutComponentBase

<MudNavMenu Class="nav-menu">

    <MudNavLink Href="#" Icon="@Icons.Material.Filled.Home" Match="NavLinkMatch.All">
        Home
        @* Navigate to: /home *@
    </MudNavLink>

    @if (!_isLoggedIn)
    {
        <MudNavLink Href="/auth">
            Login
        </MudNavLink>
    }
    
    @if (_isLoggedIn)
    {

        <MudNavLink Href="#">
            Profile
            @* Navigate to: /profile *@
        </MudNavLink>

        <MudNavLink Href="#">
            Settings
            @* Navigate to: /settings *@
        </MudNavLink>

        <MudNavLink Href="#">
            Notifications
            @* Navigate to: /notifications *@
        </MudNavLink>

        <MudNavLink Href="#">
            Help
            @* Navigate to: /help *@
        </MudNavLink>

        <MudNavLink Href="#">
            About
            @* Navigate to: /about *@
        </MudNavLink>

        <MudNavLink Href="#">
            Logout
            @* Navigate to: /logout *@
        </MudNavLink>
    }


</MudNavMenu>

@code {

    [Inject] AuthenticationStateProvider AuthStateProvider { get; set; }
    private bool  _isLoggedIn = false;
    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthStateProvider.GetAuthenticationStateAsync();
        _isLoggedIn = authState.User.Identity.IsAuthenticated;
    }

}

<style>
.nav-menu {
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
    padding: 0;
    margin: 0;
}

.nav-menu .mud-nav-link {
    color: white; /* text color inside the blue left panel */
    margin: 0;
    padding: 1rem;
    border-bottom: 1px solid rgba(255,255,255,0.2); /* subtle divider */
    transition: background-color 0.2s;
}

.nav-menu .mud-nav-link:hover {
    background-color: rgba(255,255,255,0.1);
    text-decoration: none;
}
</style>

Create Database and Migrate

dotnet ef migrations add InitialCreate
dotnet ef database update

Any errors try this

  dotnet ef migrations remove  # repeat until none left
  rm -rf Migrations

You should be able to run now