20 KiB
20 KiB
阶段1:项目基础架构搭建
阶段概述
时间: 2周
目标: 建立完整的.NET 8项目基础架构,为后续开发提供稳定的技术基础
优先级: P0 (最高优先级)
技术选型
| 类别 | 技术方案 | 说明 |
|---|---|---|
| 框架 | .NET 8 Web API | 长期支持版本 |
| 数据库 | SQL Server 2022 | 已完成迁移 |
| ORM | Entity Framework Core 8 | 直接注入DbContext,不使用仓储模式 |
| 对象映射 | Mapster | 高性能,编译时生成映射代码 |
| 依赖注入 | Autofac | 支持模块化注册、AOP |
| 缓存 | StackExchange.Redis | 分布式缓存 |
| 日志 | Serilog | 输出到文件和控制台 |
| 文档 | Swagger/OpenAPI | API文档和测试 |
项目结构
HoneyBox/
├── src/
│ ├── HoneyBox.Api/ # Web API 入口
│ │ ├── Controllers/ # 控制器
│ │ ├── Filters/ # 过滤器(异常、验证等)
│ │ ├── Middlewares/ # 中间件
│ │ ├── appsettings.json # 配置文件
│ │ ├── appsettings.Development.json
│ │ └── Program.cs
│ │
│ ├── HoneyBox.Model/ # 数据模型层(最底层,无依赖)
│ │ ├── Entities/ # 数据库实体(EF Core生成)
│ │ │ ├── User.cs
│ │ │ ├── Goods.cs
│ │ │ ├── Order.cs
│ │ │ └── ...
│ │ ├── Models/ # DTO/请求响应模型
│ │ │ ├── User/ # 用户控制器相关
│ │ │ │ ├── GetUserInfo.cs # GetUserInfoReq + GetUserInfoResp
│ │ │ │ ├── UpdateUser.cs # UpdateUserReq + UpdateUserResp
│ │ │ │ └── ...
│ │ │ ├── Goods/ # 商品控制器相关
│ │ │ │ ├── GetGoodsList.cs
│ │ │ │ └── ...
│ │ │ ├── Order/ # 订单控制器相关
│ │ │ │ └── ...
│ │ │ └── Common.cs # 通用模型(被2个以上接口复用的)
│ │ ├── Data/ # DbContext
│ │ │ └── HoneyBoxDbContext.cs
│ │ └── Base/ # 基类定义
│ │ └── ApiResponse.cs # 统一响应基类
│ │
│ ├── HoneyBox.Core/ # 核心业务层
│ │ ├── Services/ # 业务服务实现
│ │ ├── Interfaces/ # 服务接口定义
│ │ ├── Mappings/ # Mapster映射配置
│ │ └── Constants/ # 常量定义
│ │
│ └── HoneyBox.Infrastructure/ # 基础设施层
│ ├── Cache/ # Redis缓存服务
│ │ ├── ICacheService.cs
│ │ └── RedisCacheService.cs
│ ├── External/ # 外部服务集成
│ │ ├── WeChat/ # 微信服务
│ │ ├── Payment/ # 支付服务
│ │ └── Sms/ # 短信服务
│ └── Modules/ # Autofac模块
│ ├── ServiceModule.cs
│ └── InfrastructureModule.cs
│
└── HoneyBox.sln
项目依赖关系
HoneyBox.Api
├── HoneyBox.Core
└── HoneyBox.Model
HoneyBox.Core(业务层,依赖数据和基础设施)
├── HoneyBox.Model
└── HoneyBox.Infrastructure
HoneyBox.Infrastructure(外部基础设施,独立)
└── 无依赖
HoneyBox.Model(数据层,最底层)
└── 无依赖
详细任务清单
1.1 项目结构搭建 (2天)
创建解决方案
# 创建解决方案
dotnet new sln -n HoneyBox
# 创建项目
dotnet new webapi -n HoneyBox.Api -o src/HoneyBox.Api
dotnet new classlib -n HoneyBox.Model -o src/HoneyBox.Model
dotnet new classlib -n HoneyBox.Core -o src/HoneyBox.Core
dotnet new classlib -n HoneyBox.Infrastructure -o src/HoneyBox.Infrastructure
# 添加到解决方案
dotnet sln add src/HoneyBox.Api
dotnet sln add src/HoneyBox.Model
dotnet sln add src/HoneyBox.Core
dotnet sln add src/HoneyBox.Infrastructure
# 添加项目引用
dotnet add src/HoneyBox.Api reference src/HoneyBox.Model
dotnet add src/HoneyBox.Api reference src/HoneyBox.Core
dotnet add src/HoneyBox.Core reference src/HoneyBox.Model
dotnet add src/HoneyBox.Core reference src/HoneyBox.Infrastructure
NuGet包配置
HoneyBox.Model(最底层)
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
</ItemGroup>
HoneyBox.Infrastructure(独立,无项目依赖)
<ItemGroup>
<PackageReference Include="StackExchange.Redis" Version="2.7.0" />
<PackageReference Include="Autofac" Version="8.0.0" />
</ItemGroup>
HoneyBox.Core
<ItemGroup>
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.1" />
</ItemGroup>
HoneyBox.Api
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
</ItemGroup>
1.2 数据库连接配置 (2天)
配置文件
// appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=192.168.195.15;uid=sa;pwd=Dbt@com@123;Database=honey_box;MultipleActiveResultSets=true;pooling=true;min pool size=5;max pool size=32767;connect timeout=20;Encrypt=True;TrustServerCertificate=True;",
"Redis": "192.168.195.15:6379,defaultDatabase=0,password=,connectTimeout=5000"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning"
}
}
}
生成实体模型
cd src/HoneyBox.Model
dotnet ef dbcontext scaffold "Server=192.168.195.15;uid=sa;pwd=Dbt@com@123;Database=honey_box;MultipleActiveResultSets=true;pooling=true;min pool size=5;max pool size=32767;connect timeout=20;Encrypt=True;TrustServerCertificate=True;" Microsoft.EntityFrameworkCore.SqlServer -o Entities -c HoneyBoxDbContext --context-dir Data --force
DbContext配置
// HoneyBox.Model/Data/HoneyBoxDbContext.cs
public partial class HoneyBoxDbContext : DbContext
{
public HoneyBoxDbContext(DbContextOptions<HoneyBoxDbContext> options)
: base(options)
{
}
// DbSet属性由脚手架生成
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Goods> Goods { get; set; }
public virtual DbSet<Order> Orders { get; set; }
// ... 其他表
}
统一响应基类
// HoneyBox.Model/Base/ApiResponse.cs
namespace HoneyBox.Model.Base;
/// <summary>
/// 统一响应基类
/// </summary>
public class ApiResponse
{
/// <summary>
/// 状态码,0=成功,其他=失败
/// </summary>
public int Code { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Msg { get; set; } = string.Empty;
public static ApiResponse Success(string msg = "success")
=> new() { Code = 0, Msg = msg };
public static ApiResponse Fail(string msg, int code = -1)
=> new() { Code = code, Msg = msg };
}
/// <summary>
/// 带数据的统一响应
/// </summary>
public class ApiResponse<T> : ApiResponse
{
/// <summary>
/// 响应数据
/// </summary>
public T? Data { get; set; }
public static ApiResponse<T> Success(T data, string msg = "success")
=> new() { Code = 0, Msg = msg, Data = data };
public new static ApiResponse<T> Fail(string msg, int code = -1)
=> new() { Code = code, Msg = msg };
}
已迁移的数据库表(共38个)
| 分类 | 表名 | 记录数 | 说明 |
|---|---|---|---|
| 用户 | users | 2,202 | 用户主表 |
| 用户 | user_accounts | 3,452 | 用户账户 |
| 用户 | user_addresses | 51 | 收货地址 |
| 用户 | user_login_logs | 11,584 | 登录日志 |
| 商品 | goods | 503 | 商品主表 |
| 商品 | goods_items | 1,852 | 商品奖品 |
| 商品 | goods_extensions | 34 | 商品扩展 |
| 商品 | goods_types | 13 | 商品分类 |
| 商品 | prize_levels | 106 | 奖品等级 |
| 订单 | orders | 15 | 订单主表 |
| 订单 | order_items | 67 | 订单详情 |
| 订单 | deliveries | 11 | 发货记录 |
| 优惠券 | coupons | 19 | 优惠券 |
| 优惠券 | coupon_receives | 7,799 | 领取记录 |
| 钻石 | diamond_products | 5 | 钻石商品 |
| 钻石 | diamond_orders | 398 | 钻石订单 |
| VIP | vip_levels | 75 | VIP等级 |
| 系统 | configs | 25 | 系统配置 |
| 系统 | admins | 3 | 管理员 |
1.3 Autofac模块配置 (1天)
服务模块
// HoneyBox.Infrastructure/Modules/ServiceModule.cs
public class ServiceModule : Module
{
protected override void Load(ContainerBuilder builder)
{
// 自动注册所有Service
builder.RegisterAssemblyTypes(typeof(IUserService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
}
基础设施模块
// HoneyBox.Infrastructure/Modules/InfrastructureModule.cs
public class InfrastructureModule : Module
{
protected override void Load(ContainerBuilder builder)
{
// 注册缓存服务
builder.RegisterType<RedisCacheService>()
.As<ICacheService>()
.SingleInstance();
}
}
Program.cs配置Autofac
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 使用Autofac
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
containerBuilder.RegisterModule<ServiceModule>();
containerBuilder.RegisterModule<InfrastructureModule>();
});
1.4 Mapster配置 (0.5天)
映射配置
// HoneyBox.Core/Mappings/MappingConfig.cs
public static class MappingConfig
{
public static void Configure()
{
// 用户映射
TypeAdapterConfig<User, UserDto>.NewConfig()
.Map(dest => dest.UserId, src => src.Id)
.Map(dest => dest.Avatar, src => src.Headimg);
// 商品映射
TypeAdapterConfig<Goods, GoodsDto>.NewConfig()
.Map(dest => dest.Image, src => src.Imgurl);
}
}
// Program.cs中注册
MappingConfig.Configure();
builder.Services.AddMapster();
DTO文件示例
// HoneyBox.Model/Models/User/GetUserInfo.cs
using HoneyBox.Model.Base;
namespace HoneyBox.Model.Models.User;
/// <summary>
/// 获取用户信息 - 请求
/// </summary>
public class GetUserInfoReq
{
public int UserId { get; set; }
}
/// <summary>
/// 获取用户信息 - 响应
/// </summary>
public class GetUserInfoResp : ApiResponse<GetUserInfoData> { }
public class GetUserInfoData
{
public int UserId { get; set; }
public string Nickname { get; set; } = string.Empty;
public string Avatar { get; set; } = string.Empty;
public decimal Money { get; set; }
public decimal Integral { get; set; }
public int Vip { get; set; }
}
// HoneyBox.Model/Models/Common.cs
using HoneyBox.Model.Base;
namespace HoneyBox.Model.Models;
/// <summary>
/// 通用用户信息(被多个接口复用)
/// </summary>
public class UserDto
{
public int UserId { get; set; }
public string Nickname { get; set; } = string.Empty;
public string Avatar { get; set; } = string.Empty;
}
/// <summary>
/// 通用商品信息(被多个接口复用)
/// </summary>
public class GoodsDto
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public string Image { get; set; } = string.Empty;
public decimal Price { get; set; }
}
/// <summary>
/// 分页请求基类
/// </summary>
public class PageReq
{
public int Page { get; set; } = 1;
public int PageSize { get; set; } = 20;
}
/// <summary>
/// 分页响应
/// </summary>
public class PageData<T>
{
public List<T> List { get; set; } = new();
public int Total { get; set; }
public int Page { get; set; }
public int PageSize { get; set; }
}
/// <summary>
/// 分页响应(带统一格式)
/// </summary>
public class PageResp<T> : ApiResponse<PageData<T>> { }
控制器使用示例
// HoneyBox.Api/Controllers/UserController.cs
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpGet("info")]
public async Task<GetUserInfoResp> GetUserInfo([FromQuery] GetUserInfoReq req)
{
var data = await _userService.GetUserInfoAsync(req.UserId);
return ApiResponse<GetUserInfoData>.Success(data) as GetUserInfoResp
?? new GetUserInfoResp { Code = 0, Msg = "success", Data = data };
}
}
1.5 Redis缓存配置 (1天)
缓存服务接口
// HoneyBox.Infrastructure/Cache/ICacheService.cs
public interface ICacheService
{
Task<T?> GetAsync<T>(string key);
Task SetAsync<T>(string key, T value, TimeSpan? expiry = null);
Task RemoveAsync(string key);
Task<bool> ExistsAsync(string key);
}
Redis实现
// HoneyBox.Infrastructure/Cache/RedisCacheService.cs
public class RedisCacheService : ICacheService
{
private readonly IDatabase _database;
public RedisCacheService(IConfiguration configuration)
{
var connection = ConnectionMultiplexer.Connect(
configuration.GetConnectionString("Redis")!);
_database = connection.GetDatabase();
}
public async Task<T?> GetAsync<T>(string key)
{
var value = await _database.StringGetAsync(key);
return value.HasValue ? JsonSerializer.Deserialize<T>(value!) : default;
}
public async Task SetAsync<T>(string key, T value, TimeSpan? expiry = null)
{
var json = JsonSerializer.Serialize(value);
await _database.StringSetAsync(key, json, expiry);
}
public async Task RemoveAsync(string key)
{
await _database.KeyDeleteAsync(key);
}
public async Task<bool> ExistsAsync(string key)
{
return await _database.KeyExistsAsync(key);
}
}
1.6 Serilog日志配置 (0.5天)
配置文件
// appsettings.json
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "logs/log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 30,
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
}
}
]
}
}
Program.cs配置
// Program.cs
builder.Host.UseSerilog((context, configuration) =>
configuration.ReadFrom.Configuration(context.Configuration));
1.7 中间件和过滤器 (1天)
全局异常处理
// HoneyBox.Api/Filters/GlobalExceptionFilter.cs
using HoneyBox.Model.Base;
public class GlobalExceptionFilter : IExceptionFilter
{
private readonly ILogger<GlobalExceptionFilter> _logger;
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
{
_logger = logger;
}
public void OnException(ExceptionContext context)
{
_logger.LogError(context.Exception, "未处理的异常");
context.Result = new JsonResult(ApiResponse.Fail("服务器内部错误", 500));
context.ExceptionHandled = true;
}
}
统一响应格式
所有接口返回格式统一为:
{
"code": 0,
"msg": "success",
"data": { ... }
}
1.8 Swagger配置 (0.5天)
// Program.cs
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "HoneyBox API",
Version = "v1",
Description = "友达赏抽奖系统API"
});
// JWT认证配置
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Token,格式: Bearer {token}",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
1.9 完整Program.cs
using Autofac;
using Autofac.Extensions.DependencyInjection;
using HoneyBox.Api.Filters;
using HoneyBox.Core.Mappings;
using HoneyBox.Model.Data;
using HoneyBox.Infrastructure.Modules;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using Serilog;
var builder = WebApplication.CreateBuilder(args);
// Serilog
builder.Host.UseSerilog((context, configuration) =>
configuration.ReadFrom.Configuration(context.Configuration));
// Autofac
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
containerBuilder.RegisterModule<ServiceModule>();
containerBuilder.RegisterModule<InfrastructureModule>();
});
// DbContext
builder.Services.AddDbContext<HoneyBoxDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// Mapster
MappingConfig.Configure();
builder.Services.AddMapster();
// Controllers
builder.Services.AddControllers(options =>
{
options.Filters.Add<GlobalExceptionFilter>();
});
// Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "HoneyBox API", Version = "v1" });
});
// CORS
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAll", policy =>
policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseSerilogRequestLogging();
app.UseCors("AllowAll");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
交付成果
验证接口
健康检查
GET /api/health
Response: 200 OK
{
"code": 0,
"message": "success",
"data": {
"status": "Healthy",
"database": "Connected",
"redis": "Connected",
"timestamp": "2026-01-02T10:00:00Z"
}
}
验收标准
- 项目可以正常编译和运行
- Swagger文档可以正常访问 (http://localhost:5000/swagger)
- 数据库连接正常(SQL Server 2022)
- Redis连接正常
- 日志输出到控制台和文件
- Autofac依赖注入工作正常
- Mapster对象映射工作正常
下一阶段准备
为阶段2(用户认证系统)准备:
- JWT认证配置基础
- 微信SDK集成准备
- 用户服务接口定义
阶段1完成标志: 所有验收标准通过,基础架构稳定运行。