说明:采用简约分层(适合单人 / 中小项目,不重型 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
关键核心代码片段
- 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="最新稳定版" />
- 扩展 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;
}
数据库上下文 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()); } } }
- appsettings.json Postgres 连接串
"ConnectionStrings": {
"DefaultConnection": "Host=127.0.0.1;Port=5432;Database=xyblog;Username=postgres;Password=123456"
}
- 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();- _Imports.razor 全局引用
@using BootstrapBlazor
@using BootstrapBlazor.Components
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Identity
@inject AuthenticationStateProvider AuthStateProvider
- 权限控制示例页面 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)