经典三层架构 .NET 8 实战:从零构建用户管理系统,5个核心类实现CRUD 经典三层架构 .NET 8 实战从零构建用户管理系统在软件开发领域分层架构一直是构建可维护、可扩展应用程序的黄金标准。而经典的三层架构Presentation Layer、Business Logic Layer、Data Access Layer更是.NET生态系统中经久不衰的设计模式。本文将带您使用最新的.NET 8技术栈从零开始实现一个完整的用户管理系统通过5个核心类演示CRUD操作的全过程。1. 环境准备与项目结构在开始编码之前我们需要确保开发环境配置正确。以下是使用Visual Studio 2022创建项目的步骤dotnet new sln -n UserManagementSystem dotnet new classlib -n UserManagementSystem.Models dotnet new classlib -n UserManagementSystem.DAL dotnet new classlib -n UserManagementSystem.BLL dotnet new webapi -n UserManagementSystem.API项目引用关系配置dotnet add UserManagementSystem.API reference UserManagementSystem.BLL dotnet add UserManagementSystem.BLL reference UserManagementSystem.DAL dotnet add UserManagementSystem.DAL reference UserManagementSystem.Models解决方案最终结构如下UserManagementSystem.sln ├── UserManagementSystem.API # 表现层 ├── UserManagementSystem.BLL # 业务逻辑层 ├── UserManagementSystem.DAL # 数据访问层 └── UserManagementSystem.Models # 实体层提示现代.NET开发推荐使用依赖注入来管理各层之间的依赖关系这能显著提高代码的可测试性和可维护性。2. 核心模型设计与数据库映射实体模型是贯穿三层架构的数据载体我们首先定义用户实体// UserManagementSystem.Models/User.cs namespace UserManagementSystem.Models; public class User { public int Id { get; set; } [Required, StringLength(50)] public string Username { get; set; } [EmailAddress, StringLength(100)] public string Email { get; set; } [DataType(DataType.Password)] public string PasswordHash { get; set; } public DateTime CreatedAt { get; set; } DateTime.UtcNow; public DateTime? LastLogin { get; set; } public bool IsActive { get; set; } true; }对应的数据库表SQL脚本CREATE TABLE Users ( Id INT PRIMARY KEY IDENTITY(1,1), Username NVARCHAR(50) NOT NULL, Email NVARCHAR(100) NOT NULL, PasswordHash NVARCHAR(255) NOT NULL, CreatedAt DATETIME2 NOT NULL DEFAULT GETUTCDATE(), LastLogin DATETIME2 NULL, IsActive BIT NOT NULL DEFAULT 1, CONSTRAINT UQ_Users_Username UNIQUE (Username), CONSTRAINT UQ_Users_Email UNIQUE (Email) );实体层在三层架构中的作用实现数据封装Encapsulation作为各层之间数据传输的载体保持数据结构的一致性提供数据验证的基础3. 数据访问层实现数据访问层采用Repository模式结合Entity Framework Core 8// UserManagementSystem.DAL/Repositories/UserRepository.cs using Microsoft.EntityFrameworkCore; using UserManagementSystem.Models; namespace UserManagementSystem.DAL.Repositories; public interface IUserRepository { TaskUser GetByIdAsync(int id); TaskIEnumerableUser GetAllAsync(); Task AddAsync(User user); Task UpdateAsync(User user); Task DeleteAsync(int id); } public class UserRepository : IUserRepository { private readonly AppDbContext _context; public UserRepository(AppDbContext context) { _context context; } public async TaskUser GetByIdAsync(int id) { return await _context.Users.FindAsync(id); } public async TaskIEnumerableUser GetAllAsync() { return await _context.Users.ToListAsync(); } public async Task AddAsync(User user) { await _context.Users.AddAsync(user); await _context.SaveChangesAsync(); } public async Task UpdateAsync(User user) { _context.Users.Update(user); await _context.SaveChangesAsync(); } public async Task DeleteAsync(int id) { var user await GetByIdAsync(id); if (user ! null) { _context.Users.Remove(user); await _context.SaveChangesAsync(); } } }DbContext配置// UserManagementSystem.DAL/Data/AppDbContext.cs using Microsoft.EntityFrameworkCore; using UserManagementSystem.Models; namespace UserManagementSystem.DAL.Data; public class AppDbContext : DbContext { public AppDbContext(DbContextOptionsAppDbContext options) : base(options) { } public DbSetUser Users { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.EntityUser(entity { entity.HasIndex(u u.Username).IsUnique(); entity.HasIndex(u u.Email).IsUnique(); entity.Property(u u.CreatedAt) .HasDefaultValueSql(GETUTCDATE()); }); } }数据访问层最佳实践每个Repository对应一个聚合根使用异步方法提高吞吐量实现明确的接口便于单元测试将数据库特定操作限制在本层内4. 业务逻辑层设计业务逻辑层处理核心业务规则是三层架构中最体现价值的部分// UserManagementSystem.BLL/Services/UserService.cs using UserManagementSystem.DAL.Repositories; using UserManagementSystem.Models; namespace UserManagementSystem.BLL.Services; public class UserService { private readonly IUserRepository _userRepository; public UserService(IUserRepository userRepository) { _userRepository userRepository; } public async TaskUser GetUserByIdAsync(int id) { if (id 0) throw new ArgumentException(Invalid user ID); return await _userRepository.GetByIdAsync(id); } public async TaskIEnumerableUser GetAllUsersAsync() { return await _userRepository.GetAllAsync(); } public async Task CreateUserAsync(User user) { if (user null) throw new ArgumentNullException(nameof(user)); // 业务规则密码必须哈希处理 user.PasswordHash HashPassword(user.PasswordHash); await _userRepository.AddAsync(user); } public async Task UpdateUserAsync(User user) { if (user null) throw new ArgumentNullException(nameof(user)); var existingUser await _userRepository.GetByIdAsync(user.Id); if (existingUser null) throw new KeyNotFoundException(User not found); // 保留原始密码哈希如果不修改密码 if (string.IsNullOrEmpty(user.PasswordHash)) user.PasswordHash existingUser.PasswordHash; else user.PasswordHash HashPassword(user.PasswordHash); await _userRepository.UpdateAsync(user); } public async Task DeleteUserAsync(int id) { if (id 0) throw new ArgumentException(Invalid user ID); await _userRepository.DeleteAsync(id); } private static string HashPassword(string password) { // 实际项目中应使用更安全的哈希算法如PBKDF2 return Convert.ToBase64String( System.Security.Cryptography.SHA256.HashData( System.Text.Encoding.UTF8.GetBytes(password))); } }业务层应关注业务规则的执行数据验证和转换事务管理异常处理与其他服务的协调5. 表现层API实现使用ASP.NET Core Web API构建RESTful接口// UserManagementSystem.API/Controllers/UsersController.cs using Microsoft.AspNetCore.Mvc; using UserManagementSystem.BLL.Services; using UserManagementSystem.Models; namespace UserManagementSystem.API.Controllers; [ApiController] [Route(api/[controller])] public class UsersController : ControllerBase { private readonly UserService _userService; public UsersController(UserService userService) { _userService userService; } [HttpGet] public async TaskIActionResult GetAllUsers() { var users await _userService.GetAllUsersAsync(); return Ok(users); } [HttpGet({id})] public async TaskIActionResult GetUserById(int id) { var user await _userService.GetUserByIdAsync(id); return user ! null ? Ok(user) : NotFound(); } [HttpPost] public async TaskIActionResult CreateUser([FromBody] User user) { if (!ModelState.IsValid) return BadRequest(ModelState); await _userService.CreateUserAsync(user); return CreatedAtAction(nameof(GetUserById), new { id user.Id }, user); } [HttpPut({id})] public async TaskIActionResult UpdateUser(int id, [FromBody] User user) { if (id ! user.Id) return BadRequest(ID mismatch); if (!ModelState.IsValid) return BadRequest(ModelState); try { await _userService.UpdateUserAsync(user); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } } [HttpDelete({id})] public async TaskIActionResult DeleteUser(int id) { try { await _userService.DeleteUserAsync(id); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } } }依赖注入配置// UserManagementSystem.API/Program.cs using Microsoft.EntityFrameworkCore; using UserManagementSystem.DAL.Data; using UserManagementSystem.DAL.Repositories; var builder WebApplication.CreateBuilder(args); // 添加服务到容器 builder.Services.AddDbContextAppDbContext(options options.UseSqlServer(builder.Configuration.GetConnectionString(DefaultConnection))); builder.Services.AddScopedIUserRepository, UserRepository(); builder.Services.AddScopedUserService(); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app builder.Build(); // 配置HTTP请求管道 if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();表现层最佳实践保持控制器精简处理HTTP状态码实现输入验证使用DTO进行数据传递处理跨域问题6. 层间通信与性能优化三层架构中各层的交互方式直接影响系统性能。以下是几种优化策略DTO模式应用// UserManagementSystem.Models/DTOs/UserDTO.cs public class UserDTO { public int Id { get; set; } public string Username { get; set; } public string Email { get; set; } public DateTime CreatedAt { get; set; } } // 在BLL层添加映射方法 public UserDTO MapToDTO(User user) { return new UserDTO { Id user.Id, Username user.Username, Email user.Email, CreatedAt user.CreatedAt }; }缓存策略实现// 装饰器模式实现缓存 public class CachedUserService : IUserService { private readonly IUserService _innerService; private readonly IMemoryCache _cache; public CachedUserService(IUserService innerService, IMemoryCache cache) { _innerService innerService; _cache cache; } public async TaskUser GetUserByIdAsync(int id) { string cacheKey $user_{id}; return await _cache.GetOrCreateAsync(cacheKey, entry { entry.AbsoluteExpirationRelativeToNow TimeSpan.FromMinutes(5); return _innerService.GetUserByIdAsync(id); }); } }性能对比表格优化策略请求延迟数据库负载实现复杂度基础实现高高低DTO模式中中中缓存策略低低高7. 测试策略与部署方案完整的系统需要可靠的测试和部署流程单元测试示例// UserManagementSystem.BLL.Tests/UserServiceTests.cs using Moq; using UserManagementSystem.DAL.Repositories; using UserManagementSystem.Models; namespace UserManagementSystem.BLL.Tests; public class UserServiceTests { private readonly MockIUserRepository _mockRepo; private readonly UserService _userService; public UserServiceTests() { _mockRepo new MockIUserRepository(); _userService new UserService(_mockRepo.Object); } [Fact] public async Task GetUserById_ValidId_ReturnsUser() { // Arrange var testUser new User { Id 1, Username test }; _mockRepo.Setup(x x.GetByIdAsync(1)).ReturnsAsync(testUser); // Act var result await _userService.GetUserByIdAsync(1); // Assert Assert.Equal(testUser, result); _mockRepo.Verify(x x.GetByIdAsync(1), Times.Once); } }集成测试配置// UserManagementSystem.API.Tests/UsersControllerTests.cs using Microsoft.AspNetCore.Mvc; using Moq; using UserManagementSystem.BLL.Services; using UserManagementSystem.Models; namespace UserManagementSystem.API.Tests; public class UsersControllerTests { private readonly MockUserService _mockService; private readonly UsersController _controller; public UsersControllerTests() { _mockService new MockUserService(Mock.OfIUserRepository()); _controller new UsersController(_mockService.Object); } [Fact] public async Task GetUserById_ExistingId_ReturnsOk() { // Arrange var testUser new User { Id 1 }; _mockService.Setup(x x.GetUserByIdAsync(1)).ReturnsAsync(testUser); // Act var result await _controller.GetUserById(1); // Assert var okResult Assert.IsTypeOkObjectResult(result); Assert.Equal(testUser, okResult.Value); } }Docker部署配置# Dockerfile FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY [UserManagementSystem.API/UserManagementSystem.API.csproj, UserManagementSystem.API/] COPY [UserManagementSystem.BLL/UserManagementSystem.BLL.csproj, UserManagementSystem.BLL/] COPY [UserManagementSystem.DAL/UserManagementSystem.DAL.csproj, UserManagementSystem.DAL/] COPY [UserManagementSystem.Models/UserManagementSystem.Models.csproj, UserManagementSystem.Models/] RUN dotnet restore UserManagementSystem.API/UserManagementSystem.API.csproj COPY . . WORKDIR /src/UserManagementSystem.API RUN dotnet build UserManagementSystem.API.csproj -c Release -o /app/build FROM build AS publish RUN dotnet publish UserManagementSystem.API.csproj -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --frompublish /app/publish . ENTRYPOINT [dotnet, UserManagementSystem.API.dll]8. 架构演进与扩展思考随着业务复杂度增加经典三层架构可能需要演进向领域驱动设计过渡引入领域层Domain Layer使用聚合根管理复杂关系实现领域事件采用CQRS模式微服务拆分可能graph TD A[用户服务] -- B[API网关] C[权限服务] -- B D[通知服务] -- B技术栈升级路径ORM从EF Core到Dapper的混合使用缓存引入Redis二级缓存搜索集成Elasticsearch消息队列使用RabbitMQ处理异步任务在实际项目中我们发现三层架构最容易被误用的地方是业务逻辑层变成了简单的透传层。正确的做法应该是将核心业务规则、验证逻辑、工作流控制等都放在这一层使其真正成为系统的大脑。