.NET 8 Blazor Server + BootstrapBlazor + PostgreSQL + ASP.NET Core Identity 标准目录结构

.NET 8 Blazor Server + BootstrapBlazor + PostgreSQL + ASP.NET Core Identity 标准目录结构

芯宇宙技术社
2026-07-31 / 0 评论 / 3 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2026年07月31日,已超过56天没有更新,若内容或图片失效,请留言反馈。

说明:采用简约分层(适合单人 / 中小项目,不重型 DDD,避免过度拆分)
技术栈:

  • .NET 8 Blazor Server
  • BootstrapBlazor UI 组件库
  • EntityFramework Core + PostgreSQL(Npgsql)
  • ASP.NET Core Identity 身份认证(用户 / 角色 / 登录、权限)
  • 依赖注入、Repository 模式可选(下面提供两套方案:【最简版】、【分层整洁版】)

方案一:整洁分层推荐(优先使用)
项目名称:XyBlog.Web(单项目分层,Blazor Server 常用,不用拆多解决方案项目)

XyBlog.Web/
├── App.razor                          # 根组件
├── Program.cs                         # 程序入口,服务注册(Identity、BootstrapBlazor、EF、Postgres)
├── appsettings.json                   # Postgres连接字符串、Identity配置
├── appsettings.Development.json
├── Properties/
│   └── launchSettings.json
├── wwwroot/                           # 静态资源
│   ├── css/
│   ├── js/
│   └── favicon.ico
├── Data/                              # EF Core & Identity 数据层
│   ├── Migrations/                    # EF迁移文件(PostgreSQL)
│   ├── AppDbContext.cs                # 数据库上下文,继承IdentityDbContext<TUser>
│   ├── AppIdentityUser.cs             # 扩展Identity用户实体(自定义字段:头像、昵称等)
│   └── SeedData.cs                    # 初始化超级管理员种子数据
├── Models/                            # 实体、DTO、ViewModel
│   ├── Entities/                      # 业务数据库实体(文章、分类等)
│   │   ├── Article.cs
│   │   └── Category.cs
│   └── Dtos/                          # 页面交互DTO,不和数据库实体耦合
│       ├── ArticleDto.cs
│       └── LoginDto.cs
├── Services/                          # 业务逻辑层(接口+实现,DI注入)
│   ├── Interfaces/
│   │   ├── IArticleService.cs
│   │   └── ICommonService.cs
│   └── Implementations/
│       ├── ArticleService.cs
│       └── CommonService.cs
├── Repositories/【可选】如需ORM隔离可增加
│   ├── IRepository.cs
│   └── EfRepository.cs
├── Shared/                            # 全局共享Razor组件
│   ├── MainLayout.razor              # 主布局(BootstrapBlazor布局容器、侧边菜单)
│   ├── NavMenu.razor                  # 侧边导航
│   ├── LoginLayout.razor              # 登录页独立布局
│   └── Components/                    # 公共小组件(弹窗、分页、上传组件)
│       ├── ConfirmDialog.razor
│       └── AvatarUpload.razor
├── Pages/                             # Blazor页面(路由页面)
│   ├── Index.razor                    # 首页
│   ├── Error.razor
│   ├── Auth/                          # Identity认证页面
│   │   ├── Login.razor
│   │   ├── Register.razor
│   │   ├── Logout.razor
│   │   └── Profile.razor              # 用户资料修改
│   ├── Admin/                         # 后台管理页面(增加Authorize权限标签)
│   │   ├── ArticleList.razor
│   │   ├── ArticleEdit.razor
│   │   └── UserManage.razor
│   └── Articles/                      # 前台文章页面
│       ├── ArticleDetail.razor
│       └── ArticleList.razor
├── Extensions/                        # 扩展方法
│   ├── ServiceCollectionExtensions.cs # 统一注册:BootstrapBlazor、Identity、DbContext
│   └── StringExtensions.cs
├── Utils/                             # 工具类
│   ├── FileHelper.cs
│   └── DateTimeHelper.cs
└── Constants/                         # 常量、角色名称
    └── RoleNames.cs                   // Admin, Member

方案二:极简结构(快速原型开发)


XyBlog.Web/
├── Data/
│   ├── Migrations/
│   ├── AppDbContext.cs
│   └── AppIdentityUser.cs
├── Models/
├── Shared/
├── Pages/
│   ├── Auth/
│   ├── Admin/
│   └── Index.razor
├── Utils/
├── wwwroot
├── Program.cs

关键核心代码片段

  1. NuGet 必备包
<!-- EF PostgreSQL -->
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.x" />
<!-- Identity -->
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.x" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.x" />
<!-- BootstrapBlazor -->
<PackageReference Include="BootstrapBlazor" Version="最新稳定版" />
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="最新稳定版" />
  1. 扩展 Identity 用户实体 AppIdentityUser.cs
using Microsoft.AspNetCore.Identity;

namespace XyBlog.Web.Data;

public class AppIdentityUser : IdentityUser<Guid>
{
    public string NickName { get; set; } = string.Empty;
    public string Avatar { get; set; } = string.Empty;
    public DateTime CreateTime { get; set; } = DateTime.Now;
}
  1. 数据库上下文 AppDbContext.cs

    
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore;
    using XyBlog.Web.Models.Entities;
    
    namespace XyBlog.Web.Data;
    
    public class AppDbContext : IdentityDbContext<AppIdentityUser, IdentityRole<Guid>, Guid>
    {
     public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
     {
     }
    
     public DbSet<Article> Articles { get; set; }
     public DbSet<Category> Categories { get; set; }
    
     protected override void OnModelCreating(ModelBuilder builder)
     {
         base.OnModelCreating(builder);
         // PostgreSQL 小写表名(推荐)
         foreach (var entity in builder.Model.GetEntityTypes())
         {
             entity.SetTableName(entity.DisplayName().ToLower());
         }
     }
    }
    
  1. appsettings.json Postgres 连接串

"ConnectionStrings": {
  "DefaultConnection": "Host=127.0.0.1;Port=5432;Database=xyblog;Username=postgres;Password=123456"
}
  1. Program.cs 核心注册(重点:Blazor Server + Identity + BootstrapBlazor + Postgres)
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using BootstrapBlazor;
using XyBlog.Web.Data;

var builder = WebApplication.CreateBuilder(args);

// Add DbContext PostgreSQL
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseNpgsql(connectionString));

// Identity 配置
builder.Services.AddDefaultIdentity<AppIdentityUser>(options =>
    {
        options.Password.RequireDigit = false;
        options.Password.RequiredLength = 6;
        options.Password.RequireNonAlphanumeric = false;
    })
    .AddRoles<IdentityRole<Guid>>()
    .AddEntityFrameworkStores<AppDbContext>();

// Blazor Server
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

// BootstrapBlazor
builder.Services.AddBootstrapBlazor();

// 业务服务批量注入
// builder.Services.AddScoped<IArticleService, ArticleService>();

var app = builder.Build();

// 自动迁移+初始化种子(开发环境可选)
using var scope = app.Services.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
dbContext.Database.Migrate();
// SeedData.Initialize(scope.ServiceProvider);

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
}

app.UseStaticFiles();
app.UseAntiforgery();

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

app.Run();
  1. _Imports.razor 全局引用
@using BootstrapBlazor
@using BootstrapBlazor.Components
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Identity
@inject AuthenticationStateProvider AuthStateProvider
  1. 权限控制示例页面 Admin/UserManage.razor
@attribute [Authorize(Roles = "Admin")]
@inject UserManager<AppIdentityUser> UserManager

配套操作命令(EF 迁移 PostgreSQL)


# 创建迁移
Add-Migration InitDb
# 应用迁移到Postgres数据库
Update-Database

架构小建议

Blazor Server 不要把业务逻辑写在 razor 页面代码块,全部抽入Services,方便单元测试;
DTO 与数据库实体分离,页面绝对不直接返回数据库实体;
Identity 尽量使用 Guid 主键(默认 string 可以改成 Guid,Postgres 存储更友好,上面代码已支持);
BootstrapBlazor 弹窗、表格、分页统一封装到 Shared/Components 复用;
Blazor Server 注意Scoped 服务生命周期,不要使用单例 DbContext。

0

评论 (0)

取消