HaniBlindBox/docs/API迁移详细文档/阶段1-项目基础架构.md
2026-01-02 15:46:56 +08:00

20 KiB
Raw Blame History

阶段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完成标志: 所有验收标准通过,基础架构稳定运行。