测试
This commit is contained in:
488
.trae/rules/project_rules.md
Normal file
488
.trae/rules/project_rules.md
Normal file
@@ -0,0 +1,488 @@
|
|||||||
|
# 实施计划
|
||||||
|
|
||||||
|
- [x] 1. 初始化项目结构
|
||||||
|
- 创建后端.NET 9.0解决方案,包含API、Core、Infrastructure和Application四个项目层
|
||||||
|
- 创建前端Vite+Vue 3项目,配置路由、状态管理和UI组件库
|
||||||
|
- 配置MySQL数据库连接和Entity Framework Core
|
||||||
|
- 设置开发环境配置文件(appsettings.json和.env)
|
||||||
|
- _需求: 1.1, 6.1_
|
||||||
|
|
||||||
|
- [x] 2. 实现数据库层和核心实体
|
||||||
|
|
||||||
|
|
||||||
|
- [x] 2.1 创建实体类和DbContext
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 实现Category、Product、PerformanceScore、Specification、DataSource和RankingHistory实体类
|
||||||
|
- 配置AppDbContext和实体关系映射
|
||||||
|
- 配置数据库索引(Name, Model, CategoryId, PerformanceScore字段)
|
||||||
|
- _需求: 7.1, 7.2_
|
||||||
|
- [x] 2.2 创建和执行数据库迁移
|
||||||
|
|
||||||
|
|
||||||
|
- 生成初始数据库迁移文件
|
||||||
|
- 执行迁移创建数据库表结构
|
||||||
|
- 添加种子数据(初始产品类别:手机CPU、手机GPU、电脑CPU、电脑GPU)
|
||||||
|
- _需求: 1.1, 1.2, 7.1_
|
||||||
|
|
||||||
|
- [ ] 2.3 编写实体验证单元测试
|
||||||
|
- 测试实体属性验证规则
|
||||||
|
|
||||||
|
|
||||||
|
- 测试实体关系配置
|
||||||
|
|
||||||
|
|
||||||
|
- _需求: 7.1_
|
||||||
|
|
||||||
|
- [x] 3. 实现Repository层数据访问
|
||||||
|
|
||||||
|
- [ ] 3.1 创建Repository接口和实现
|
||||||
|
- 实现ICategoryRepository和CategoryRepository
|
||||||
|
- 实现IProductRepository和ProductRepository,包含分页、搜索和筛选方法
|
||||||
|
- 实现通用Repository基类
|
||||||
|
|
||||||
|
- _需求: 2.2, 4.2, 7.2_
|
||||||
|
- [ ] 3.2 实现产品查询方法
|
||||||
|
- 实现按类别获取产品列表(支持分页和排序)
|
||||||
|
- 实现产品搜索方法(按名称、型号、品牌)
|
||||||
|
- 实现产品筛选方法(按性能分数区间、发布年份)
|
||||||
|
- _需求: 2.1, 4.2, 4.3, 4.4_
|
||||||
|
- [ ] 3.3 编写Repository层单元测试
|
||||||
|
- 使用InMemory数据库测试CRUD操作
|
||||||
|
- 测试查询和筛选逻辑
|
||||||
|
- _需求: 7.2_
|
||||||
|
|
||||||
|
- [x] 4. 实现Service层业务逻辑
|
||||||
|
|
||||||
|
- [x] 4.1 创建CategoryService
|
||||||
|
|
||||||
|
|
||||||
|
- 实现获取所有类别方法
|
||||||
|
- 实现获取单个类别详情方法
|
||||||
|
- 使用AutoMapper配置DTO映射
|
||||||
|
- _需求: 1.3, 1.4, 6.1_
|
||||||
|
- [x] 4.2 创建ProductService
|
||||||
|
|
||||||
|
|
||||||
|
- 实现获取产品排名列表方法(支持分页、排序)
|
||||||
|
- 实现获取产品详情方法(包含规格参数和性能分数)
|
||||||
|
- 实现产品搜索方法
|
||||||
|
- 实现产品筛选方法
|
||||||
|
- _需求: 2.1, 2.2, 2.3, 2.4, 4.2, 4.3, 4.4_
|
||||||
|
- [x] 4.3 创建ComparisonService
|
||||||
|
|
||||||
|
|
||||||
|
- 实现产品对比方法(接受2-4个产品ID)
|
||||||
|
- 实现对比数据处理逻辑(标识最优和最差指标)
|
||||||
|
- 生成对比矩阵数据结构
|
||||||
|
|
||||||
|
- _需求: 5.1, 5.2, 5.3, 5.4_
|
||||||
|
- [ ] 4.4 编写Service层单元测试
|
||||||
|
- 测试业务逻辑正确性
|
||||||
|
|
||||||
|
|
||||||
|
- 使用Mock测试Repository依赖
|
||||||
|
|
||||||
|
|
||||||
|
- _需求: 2.1, 4.2, 5.1_
|
||||||
|
|
||||||
|
- [x] 5. 实现API Controllers
|
||||||
|
|
||||||
|
|
||||||
|
- [x] 5.1 创建CategoriesController
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 实现GET /api/categories端点
|
||||||
|
- 实现GET /api/categories/{id}端点
|
||||||
|
- 配置响应格式和状态码
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- _需求: 6.1, 6.6_
|
||||||
|
- [x] 5.2 创建ProductsController
|
||||||
|
|
||||||
|
- 实现GET /api/products端点(支持查询参数:categoryId, page, pageSize, sortBy, order)
|
||||||
|
|
||||||
|
|
||||||
|
- 实现GET /api/products/{id}端点
|
||||||
|
- 实现GET /api/products/search端点(支持查询参数:q, categoryId, manufacturer, minScore, maxScore)
|
||||||
|
- 配置FluentValidation验证查询参数
|
||||||
|
|
||||||
|
- _需求: 2.1, 2.2, 2.3, 4.2, 4.4, 6.2, 6.3, 6.4, 6.6_
|
||||||
|
- [x] 5.3 创建ComparisonController
|
||||||
|
|
||||||
|
|
||||||
|
- 实现POST /api/comparison端点
|
||||||
|
- 验证请求体(productIds数组长度2-4)
|
||||||
|
- 配置响应格式
|
||||||
|
- _需求: 5.1, 5.2, 6.5, 6.6_
|
||||||
|
- [x] 5.4 配置全局异常处理中间件
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 实现GlobalExceptionMiddleware
|
||||||
|
- 处理ValidationException、NotFoundException和通用Exception
|
||||||
|
- 返回标准化错误响应
|
||||||
|
- _需求: 6.7_
|
||||||
|
- [ ] 5.5 编写API集成测试
|
||||||
|
- 使用WebApplicationFactory测试API端点
|
||||||
|
- 测试各种查询参数组合
|
||||||
|
- 测试错误处理
|
||||||
|
- _需求: 6.1, 6.2, 6.3, 6.4, 6.5_
|
||||||
|
|
||||||
|
- [x] 6. 实现数据采集服务
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- [x] 6.1 创建DataCollectionService基础结构
|
||||||
|
|
||||||
|
|
||||||
|
- 实现IDataCollectionService接口
|
||||||
|
- 配置HttpClientFactory
|
||||||
|
- 实现数据验证和转换逻辑
|
||||||
|
- _需求: 3.1, 3.2, 3.3, 3.4_
|
||||||
|
- [x] 6.2 实现GeekBench数据采集
|
||||||
|
|
||||||
|
|
||||||
|
- 实现CollectFromGeekBenchAsync方法
|
||||||
|
- 解析GeekBench API响应或爬取排行榜页面
|
||||||
|
- 提取CPU性能数据(Single-Core和Multi-Core分数)
|
||||||
|
- 更新或插入Product和PerformanceScore数据
|
||||||
|
- _需求: 3.1, 3.4_
|
||||||
|
- [x] 6.3 实现GPU数据采集
|
||||||
|
|
||||||
|
|
||||||
|
- 实现CollectGpuDataAsync方法
|
||||||
|
- 集成3DMark或GFXBench数据源
|
||||||
|
- 提取GPU性能数据
|
||||||
|
- _需求: 3.2, 3.4_
|
||||||
|
- [x] 6.4 实现AnTuTu数据采集
|
||||||
|
|
||||||
|
|
||||||
|
- 实现CollectFromAnTuTuAsync方法
|
||||||
|
- 爬取AnTuTu排行榜数据
|
||||||
|
- 提取移动设备综合性能数据
|
||||||
|
- _需求: 3.3, 3.4_
|
||||||
|
- [x] 6.5 实现排名计算服务
|
||||||
|
|
||||||
|
|
||||||
|
- 实现RecalculateRankingsAsync方法
|
||||||
|
- 按类别和性能分数计算排名
|
||||||
|
- 更新Product的CurrentRank字段
|
||||||
|
- 记录RankingHistory历史数据
|
||||||
|
- _需求: 2.5, 7.3_
|
||||||
|
- [x] 6.6 配置错误处理和重试机制
|
||||||
|
|
||||||
|
|
||||||
|
- 实现API调用失败重试逻辑(最多3次)
|
||||||
|
- 记录详细错误日志(使用Serilog)
|
||||||
|
- 实现告警通知机制
|
||||||
|
- _需求: 3.6_
|
||||||
|
- [x] 6.7 编写数据采集服务测试
|
||||||
|
|
||||||
|
|
||||||
|
- 使用Mock测试外部API调用
|
||||||
|
- 测试数据验证逻辑
|
||||||
|
- 测试排名计算准确性
|
||||||
|
- _需求: 3.4, 3.6_
|
||||||
|
|
||||||
|
- [ ] 7. 配置后台任务调度
|
||||||
|
- [x] 7.1 集成Hangfire
|
||||||
|
|
||||||
|
|
||||||
|
- 安装Hangfire NuGet包
|
||||||
|
- 配置Hangfire使用MySQL存储
|
||||||
|
|
||||||
|
- 配置Hangfire Dashboard
|
||||||
|
|
||||||
|
- _需求: 3.5_
|
||||||
|
- [x] 7.2 创建DataSyncJob
|
||||||
|
|
||||||
|
|
||||||
|
- 实现定时数据同步任务
|
||||||
|
- 配置每24小时执行一次
|
||||||
|
|
||||||
|
- 调用DataCollectionService的各个采集方法
|
||||||
|
- 记录任务执行结果
|
||||||
|
- _需求: 3.5_
|
||||||
|
- [x] 7.3 配置数据库备份任务
|
||||||
|
|
||||||
|
- 创建DatabaseBackupJob
|
||||||
|
- 配置每周执行一次
|
||||||
|
- 实现MySQL数据库备份逻辑
|
||||||
|
- _需求: 7.5_
|
||||||
|
|
||||||
|
|
||||||
|
- [x] 8. 实现前端基础架构
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- [x] 8.1 配置Vue Router
|
||||||
|
- 创建路由配置文件
|
||||||
|
- 定义路由:首页、类别排名、产品详情、产品对比
|
||||||
|
|
||||||
|
- 配置路由懒加载
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- _需求: 2.1, 8.1_
|
||||||
|
- [x] 8.2 配置Pinia状态管理
|
||||||
|
- 创建categoryStore(管理产品类别状态)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 创建productStore(管理产品列表和详情状态)
|
||||||
|
|
||||||
|
|
||||||
|
- 创建comparisonStore(管理对比产品状态)
|
||||||
|
- _需求: 2.1, 4.1, 5.1_
|
||||||
|
- [x] 8.3 配置Axios和API服务层
|
||||||
|
|
||||||
|
|
||||||
|
- 创建Axios实例,配置baseURL和拦截器
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 实现请求拦截器(添加通用headers)
|
||||||
|
- 实现响应拦截器(统一错误处理)
|
||||||
|
|
||||||
|
|
||||||
|
- 创建categoryService、productService和comparisonService
|
||||||
|
|
||||||
|
|
||||||
|
- _需求: 6.1, 6.2, 6.3, 6.4, 6.5_
|
||||||
|
- [ ] 8.4 集成Element Plus和TailwindCSS
|
||||||
|
- 安装和配置Element Plus组件库
|
||||||
|
- 配置TailwindCSS
|
||||||
|
|
||||||
|
- 创建全局样式文件
|
||||||
|
- _需求: 8.1, 8.2_
|
||||||
|
|
||||||
|
- [x] 9. 实现前端布局组件
|
||||||
|
|
||||||
|
|
||||||
|
- [x] 9.1 创建Header组件
|
||||||
|
- 实现顶部导航栏
|
||||||
|
- 添加Logo和应用名称
|
||||||
|
- 添加产品类别导航菜单
|
||||||
|
- 实现响应式布局
|
||||||
|
- _需求: 1.4, 8.1, 8.2_
|
||||||
|
- [x] 9.2 创建Footer组件
|
||||||
|
- 显示数据来源说明
|
||||||
|
- 显示最后更新时间
|
||||||
|
- 添加数据源链接
|
||||||
|
- _需求: 10.1, 10.2, 10.4_
|
||||||
|
- [x] 9.3 创建主布局组件
|
||||||
|
- 组合Header和Footer
|
||||||
|
- 配置router-view
|
||||||
|
- 实现响应式容器
|
||||||
|
- _需求: 8.1, 8.2_
|
||||||
|
|
||||||
|
- [x] 10. 实现首页和类别选择
|
||||||
|
- [x] 10.1 创建Home视图
|
||||||
|
- 显示产品类别卡片网格
|
||||||
|
- 调用categoryStore获取类别列表
|
||||||
|
- 实现类别卡片点击跳转
|
||||||
|
- 显示每个类别的产品数量
|
||||||
|
- _需求: 1.1, 1.4_
|
||||||
|
- [x] 10.2 实现响应式布局
|
||||||
|
- 桌面端:4列网格
|
||||||
|
- 平板端:2列网格
|
||||||
|
- 手机端:1列网格
|
||||||
|
- _需求: 8.1, 8.2, 8.3_
|
||||||
|
|
||||||
|
- [x] 11. 实现产品排名列表页面
|
||||||
|
|
||||||
|
|
||||||
|
- [x] 11.1 创建CategoryRanking视图
|
||||||
|
|
||||||
|
|
||||||
|
- 根据路由参数获取categoryId
|
||||||
|
- 调用productStore获取产品列表
|
||||||
|
- 显示产品排名列表
|
||||||
|
- 实现分页组件
|
||||||
|
- _需求: 2.1, 2.5_
|
||||||
|
- [x] 11.2 创建ProductCard组件
|
||||||
|
|
||||||
|
- 显示产品缩略图、名称、型号
|
||||||
|
- 显示性能分数和排名
|
||||||
|
- 显示制造商和发布日期
|
||||||
|
- 实现点击跳转到详情页
|
||||||
|
- _需求: 2.2_
|
||||||
|
- [x] 11.3 创建ProductFilter组件
|
||||||
|
|
||||||
|
- 实现品牌筛选下拉框
|
||||||
|
- 实现性能分数区间滑块
|
||||||
|
- 实现发布年份筛选
|
||||||
|
- 实现筛选条件重置按钮
|
||||||
|
- _需求: 4.3, 4.5_
|
||||||
|
- [x] 11.4 创建ProductSearch组件
|
||||||
|
|
||||||
|
- 实现搜索输入框
|
||||||
|
- 实现搜索建议(防抖)
|
||||||
|
- 实现搜索结果高亮
|
||||||
|
- _需求: 4.1, 4.2_
|
||||||
|
- [x] 11.5 实现排序功能
|
||||||
|
|
||||||
|
- 添加排序下拉框(按性能分数、发布日期、价格)
|
||||||
|
- 实现升序/降序切换
|
||||||
|
- 调用API重新获取排序后的数据
|
||||||
|
- _需求: 2.4_
|
||||||
|
- [x] 11.6 实现产品对比选择
|
||||||
|
|
||||||
|
- 添加产品选择复选框
|
||||||
|
- 显示已选产品数量(最多4个)
|
||||||
|
- 添加"对比"按钮,跳转到对比页面
|
||||||
|
- _需求: 5.1_
|
||||||
|
|
||||||
|
- [x] 12. 实现产品详情页面
|
||||||
|
|
||||||
|
- [x] 12.1 创建ProductDetail视图
|
||||||
|
|
||||||
|
|
||||||
|
- 根据路由参数获取productId
|
||||||
|
- 调用productStore获取产品详情
|
||||||
|
- 显示产品基本信息(名称、型号、制造商、发布日期)
|
||||||
|
- 显示性能分数和当前排名
|
||||||
|
- _需求: 2.2, 2.3_
|
||||||
|
|
||||||
|
- [x] 12.2 显示规格参数
|
||||||
|
- 以表格形式展示Specifications
|
||||||
|
- 分组显示(如:处理器规格、图形规格)
|
||||||
|
- _需求: 2.2_
|
||||||
|
- [x] 12.3 显示性能测试分数
|
||||||
|
- 以卡片形式展示各项Benchmark分数
|
||||||
|
- 使用进度条可视化分数
|
||||||
|
- _需求: 2.2_
|
||||||
|
- [x] 12.4 显示数据来源信息
|
||||||
|
|
||||||
|
- 显示数据来源名称和链接
|
||||||
|
- 显示最后更新时间
|
||||||
|
- _需求: 10.2, 10.3, 10.4_
|
||||||
|
- [ ] 12.5 集成ECharts图表
|
||||||
|
- 安装vue-echarts
|
||||||
|
- 创建性能历史趋势折线图
|
||||||
|
- 创建性能指标雷达图
|
||||||
|
- 实现图表响应式
|
||||||
|
- _需求: 9.1, 9.3_
|
||||||
|
|
||||||
|
|
||||||
|
- [ ] 13. 实现产品对比页面
|
||||||
|
- [ ] 13.1 创建ProductComparison视图
|
||||||
|
- 从路由查询参数获取productIds
|
||||||
|
|
||||||
|
- 调用comparisonStore获取对比数据
|
||||||
|
- 显示对比产品的基本信息
|
||||||
|
- _需求: 5.1, 5.2_
|
||||||
|
- [ ] 13.2 创建ComparisonTable组件
|
||||||
|
- 以表格形式展示产品参数对比
|
||||||
|
- 高亮显示最优值(绿色)和最差值(红色)
|
||||||
|
- 支持横向滚动(移动端)
|
||||||
|
- _需求: 5.2, 5.4_
|
||||||
|
- [ ] 13.3 创建ComparisonChart组件
|
||||||
|
- 使用ECharts创建柱状图对比性能分数
|
||||||
|
- 使用雷达图对比多维度性能指标
|
||||||
|
- 实现图表交互(悬停显示详细数据)
|
||||||
|
- _需求: 5.3, 9.2_
|
||||||
|
|
||||||
|
- [ ] 14. 实现前端错误处理和加载状态
|
||||||
|
- [ ] 14.1 创建全局错误处理
|
||||||
|
- 在Axios拦截器中处理网络错误
|
||||||
|
- 显示Toast错误提示(使用Element Plus)
|
||||||
|
- 处理401/403/404/500等HTTP错误
|
||||||
|
- _需求: 8.4_
|
||||||
|
- [ ] 14.2 实现加载状态
|
||||||
|
- 在各个视图中添加Loading组件
|
||||||
|
- 使用Skeleton屏幕优化加载体验
|
||||||
|
- 实现数据加载失败重试按钮
|
||||||
|
- _需求: 8.4_
|
||||||
|
- [ ] 14.3 实现空状态处理
|
||||||
|
- 创建EmptyState组件
|
||||||
|
- 在无数据时显示友好提示
|
||||||
|
- 提供返回首页或重新加载按钮
|
||||||
|
- _需求: 8.4_
|
||||||
|
|
||||||
|
- [x] 15. 实现性能优化
|
||||||
|
- [x] 15.1 配置前端代码分割
|
||||||
|
- 配置Vite的代码分割策略
|
||||||
|
- 实现路由级别的懒加载
|
||||||
|
- 分离第三方库(vendor chunk)
|
||||||
|
- _需求: 8.4_
|
||||||
|
- [x] 15.2 实现图片优化
|
||||||
|
- 配置图片懒加载(使用Intersection Observer)
|
||||||
|
- 使用WebP格式图片(带降级方案)
|
||||||
|
- 实现图片占位符
|
||||||
|
- _需求: 8.4_
|
||||||
|
- [x] 15.3 配置后端缓存
|
||||||
|
- 安装StackExchange.Redis NuGet包
|
||||||
|
- 配置Redis连接
|
||||||
|
- 实现排名列表缓存(5分钟过期)
|
||||||
|
- 实现产品详情缓存(15分钟过期)
|
||||||
|
- _需求: 2.1, 2.3_
|
||||||
|
- [ ] 15.4 实现API响应压缩
|
||||||
|
- 配置Response Compression中间件
|
||||||
|
- 启用Gzip压缩
|
||||||
|
- _需求: 6.6_
|
||||||
|
- [ ] 15.5 配置数据库查询优化
|
||||||
|
- 使用AsNoTracking优化只读查询
|
||||||
|
- 实现Include预加载关联数据
|
||||||
|
- 避免N+1查询问题
|
||||||
|
- _需求: 7.2_
|
||||||
|
|
||||||
|
- [x] 16. 配置CORS和安全设置
|
||||||
|
- [x] 16.1 配置CORS策略
|
||||||
|
- 在Program.cs中配置CORS
|
||||||
|
- 允许前端域名访问
|
||||||
|
- 配置允许的HTTP方法和Headers
|
||||||
|
- _需求: 6.6_
|
||||||
|
- [ ] 16.2 配置API限流
|
||||||
|
- 安装AspNetCoreRateLimit NuGet包
|
||||||
|
- 配置IP限流规则(每分钟最多100请求)
|
||||||
|
- 配置端点级别限流
|
||||||
|
- _需求: 6.6_
|
||||||
|
- [ ] 16.3 配置输入验证
|
||||||
|
- 使用FluentValidation验证所有API输入
|
||||||
|
- 防止SQL注入(使用参数化查询)
|
||||||
|
- 清理和转义用户输入
|
||||||
|
- _需求: 6.7_
|
||||||
|
|
||||||
|
- [ ] 17. 配置日志和监控
|
||||||
|
- [ ] 17.1 配置Serilog
|
||||||
|
- 安装Serilog NuGet包
|
||||||
|
- 配置日志输出到文件和控制台
|
||||||
|
- 配置结构化日志格式
|
||||||
|
- 配置日志级别(Development: Debug, Production: Information)
|
||||||
|
- _需求: 3.6_
|
||||||
|
- [ ] 17.2 实现关键操作日志
|
||||||
|
- 记录数据采集任务执行日志
|
||||||
|
- 记录API错误日志
|
||||||
|
- 记录数据库操作异常日志
|
||||||
|
- _需求: 3.6_
|
||||||
|
- [ ] 17.3 配置Hangfire Dashboard监控
|
||||||
|
- 启用Hangfire Dashboard
|
||||||
|
- 配置Dashboard访问权限
|
||||||
|
- 监控后台任务执行状态
|
||||||
|
- _需求: 3.5_
|
||||||
|
|
||||||
|
- [ ] 18. 编写部署文档和配置
|
||||||
|
- [ ] 18.1 创建Docker配置
|
||||||
|
- 编写后端Dockerfile
|
||||||
|
- 编写前端Dockerfile
|
||||||
|
- 创建docker-compose.yml(包含API、前端、MySQL、Redis)
|
||||||
|
- _需求: 1.1_
|
||||||
|
- [ ] 18.2 创建环境配置文件
|
||||||
|
- 创建appsettings.Production.json
|
||||||
|
- 创建前端.env.production
|
||||||
|
- 配置生产环境数据库连接字符串
|
||||||
|
- 配置API密钥和外部服务配置
|
||||||
|
- _需求: 3.1, 3.2, 3.3_
|
||||||
|
- [ ] 18.3 编写部署文档
|
||||||
|
- 编写README.md(项目介绍、技术栈、功能特性)
|
||||||
|
- 编写DEPLOYMENT.md(部署步骤、环境要求、配置说明)
|
||||||
|
- 编写API文档(使用Swagger/OpenAPI)
|
||||||
|
- _需求: 1.1, 6.1, 6.2, 6.3, 6.4, 6.5_
|
||||||
26
HardwarePerformance.Tests/HardwarePerformance.Tests.csproj
Normal file
26
HardwarePerformance.Tests/HardwarePerformance.Tests.csproj
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||||
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.2" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\MinimalAPI\MinimalAPI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
97
HardwarePerformance.Tests/Services/CategoryServiceTests.cs
Normal file
97
HardwarePerformance.Tests/Services/CategoryServiceTests.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using HardwarePerformance.Models;
|
||||||
|
using HardwarePerformance.Models.DTOs;
|
||||||
|
using HardwarePerformance.Services;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Tests.Services
|
||||||
|
{
|
||||||
|
public class CategoryServiceTests
|
||||||
|
{
|
||||||
|
private readonly Mock<ICategoryRepository> _mockCategoryRepository;
|
||||||
|
private readonly Mock<IMapper> _mockMapper;
|
||||||
|
private readonly CategoryService _categoryService;
|
||||||
|
|
||||||
|
public CategoryServiceTests()
|
||||||
|
{
|
||||||
|
_mockCategoryRepository = new Mock<ICategoryRepository>();
|
||||||
|
_mockMapper = new Mock<IMapper>();
|
||||||
|
_categoryService = new CategoryService(_mockCategoryRepository.Object, _mockMapper.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetAllCategoriesAsync_ReturnsAllCategories()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var categories = new List<Category>
|
||||||
|
{
|
||||||
|
new Category { Id = 1, Name = "手机CPU", Description = "手机处理器" },
|
||||||
|
new Category { Id = 2, Name = "电脑CPU", Description = "电脑处理器" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var categoryDtos = new List<CategoryDto>
|
||||||
|
{
|
||||||
|
new CategoryDto { Id = 1, Name = "手机CPU", Description = "手机处理器" },
|
||||||
|
new CategoryDto { Id = 2, Name = "电脑CPU", Description = "电脑处理器" }
|
||||||
|
};
|
||||||
|
|
||||||
|
_mockCategoryRepository.Setup(repo => repo.GetAllAsync())
|
||||||
|
.ReturnsAsync(categories);
|
||||||
|
|
||||||
|
_mockMapper.Setup(m => m.Map<IEnumerable<CategoryDto>>(categories))
|
||||||
|
.Returns(categoryDtos);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _categoryService.GetAllCategoriesAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(2, result.Count());
|
||||||
|
_mockCategoryRepository.Verify(repo => repo.GetAllAsync(), Times.Once);
|
||||||
|
_mockMapper.Verify(m => m.Map<IEnumerable<CategoryDto>>(categories), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetCategoryByIdAsync_ExistingCategory_ReturnsCategoryDto()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var categoryId = 1;
|
||||||
|
var category = new Category { Id = categoryId, Name = "手机CPU", Description = "手机处理器" };
|
||||||
|
var categoryDto = new CategoryDto { Id = categoryId, Name = "手机CPU", Description = "手机处理器" };
|
||||||
|
|
||||||
|
_mockCategoryRepository.Setup(repo => repo.GetByIdAsync(categoryId))
|
||||||
|
.ReturnsAsync(category);
|
||||||
|
|
||||||
|
_mockMapper.Setup(m => m.Map<CategoryDto>(category))
|
||||||
|
.Returns(categoryDto);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _categoryService.GetCategoryByIdAsync(categoryId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(categoryId, result.Id);
|
||||||
|
Assert.Equal("手机CPU", result.Name);
|
||||||
|
_mockCategoryRepository.Verify(repo => repo.GetByIdAsync(categoryId), Times.Once);
|
||||||
|
_mockMapper.Verify(m => m.Map<CategoryDto>(category), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetCategoryByIdAsync_NonExistingCategory_ReturnsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var categoryId = 999;
|
||||||
|
|
||||||
|
_mockCategoryRepository.Setup(repo => repo.GetByIdAsync(categoryId))
|
||||||
|
.ReturnsAsync((Category?)null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _categoryService.GetCategoryByIdAsync(categoryId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(result);
|
||||||
|
_mockCategoryRepository.Verify(repo => repo.GetByIdAsync(categoryId), Times.Once);
|
||||||
|
_mockMapper.Verify(m => m.Map<CategoryDto>(It.IsAny<Category>()), Times.Never);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
173
HardwarePerformance.Tests/Services/ComparisonServiceTests.cs
Normal file
173
HardwarePerformance.Tests/Services/ComparisonServiceTests.cs
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using HardwarePerformance.Models;
|
||||||
|
using HardwarePerformance.Models.DTOs;
|
||||||
|
using HardwarePerformance.Services;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Tests.Services
|
||||||
|
{
|
||||||
|
public class ComparisonServiceTests
|
||||||
|
{
|
||||||
|
private readonly Mock<IProductRepository> _mockProductRepository;
|
||||||
|
private readonly Mock<IMapper> _mockMapper;
|
||||||
|
private readonly ComparisonService _comparisonService;
|
||||||
|
|
||||||
|
public ComparisonServiceTests()
|
||||||
|
{
|
||||||
|
_mockProductRepository = new Mock<IProductRepository>();
|
||||||
|
_mockMapper = new Mock<IMapper>();
|
||||||
|
_comparisonService = new ComparisonService(_mockProductRepository.Object, _mockMapper.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CompareProductsAsync_ValidProductIds_ReturnsComparisonData()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var productIds = new List<int> { 1, 2 };
|
||||||
|
|
||||||
|
var products = new List<Product>
|
||||||
|
{
|
||||||
|
new Product
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Name = "Intel Core i9",
|
||||||
|
Manufacturer = "Intel",
|
||||||
|
CategoryId = 1,
|
||||||
|
CurrentRank = 1,
|
||||||
|
ReleaseDate = DateTime.Now.AddMonths(-6),
|
||||||
|
Price = 500,
|
||||||
|
PerformanceScore = 4000,
|
||||||
|
PerformanceScores = new List<PerformanceScore>
|
||||||
|
{
|
||||||
|
new PerformanceScore { Id = 1, ProductId = 1, TestType = "Single-Core", Score = 1500 },
|
||||||
|
new PerformanceScore { Id = 2, ProductId = 1, TestType = "Multi-Core", Score = 8000 }
|
||||||
|
},
|
||||||
|
Specifications = new List<Specification>
|
||||||
|
{
|
||||||
|
new Specification { Id = 1, ProductId = 1, Name = "Cores", Value = "8" },
|
||||||
|
new Specification { Id = 2, ProductId = 1, Name = "Threads", Value = "16" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Product
|
||||||
|
{
|
||||||
|
Id = 2,
|
||||||
|
Name = "AMD Ryzen 9",
|
||||||
|
Manufacturer = "AMD",
|
||||||
|
CategoryId = 1,
|
||||||
|
CurrentRank = 2,
|
||||||
|
ReleaseDate = DateTime.Now.AddMonths(-4),
|
||||||
|
Price = 450,
|
||||||
|
PerformanceScore = 3800,
|
||||||
|
PerformanceScores = new List<PerformanceScore>
|
||||||
|
{
|
||||||
|
new PerformanceScore { Id = 3, ProductId = 2, TestType = "Single-Core", Score = 1400 },
|
||||||
|
new PerformanceScore { Id = 4, ProductId = 2, TestType = "Multi-Core", Score = 7500 }
|
||||||
|
},
|
||||||
|
Specifications = new List<Specification>
|
||||||
|
{
|
||||||
|
new Specification { Id = 3, ProductId = 2, Name = "Cores", Value = "8" },
|
||||||
|
new Specification { Id = 4, ProductId = 2, Name = "Threads", Value = "16" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var productDtos = new List<ProductDto>
|
||||||
|
{
|
||||||
|
new ProductDto
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Name = "Intel Core i9",
|
||||||
|
Manufacturer = "Intel",
|
||||||
|
CategoryId = 1,
|
||||||
|
CurrentRank = 1,
|
||||||
|
ReleaseDate = DateTime.Now.AddMonths(-6),
|
||||||
|
Price = 500,
|
||||||
|
PerformanceScore = 4000,
|
||||||
|
PerformanceScores = new List<PerformanceScore>
|
||||||
|
{
|
||||||
|
new PerformanceScore { Id = 1, ProductId = 1, TestType = "Single-Core", Score = 1500 },
|
||||||
|
new PerformanceScore { Id = 2, ProductId = 1, TestType = "Multi-Core", Score = 8000 }
|
||||||
|
},
|
||||||
|
Specifications = new List<Specification>
|
||||||
|
{
|
||||||
|
new Specification { Id = 1, ProductId = 1, Name = "Cores", Value = "8" },
|
||||||
|
new Specification { Id = 2, ProductId = 1, Name = "Threads", Value = "16" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new ProductDto
|
||||||
|
{
|
||||||
|
Id = 2,
|
||||||
|
Name = "AMD Ryzen 9",
|
||||||
|
Manufacturer = "AMD",
|
||||||
|
CategoryId = 1,
|
||||||
|
CurrentRank = 2,
|
||||||
|
ReleaseDate = DateTime.Now.AddMonths(-4),
|
||||||
|
Price = 450,
|
||||||
|
PerformanceScore = 3800,
|
||||||
|
PerformanceScores = new List<PerformanceScore>
|
||||||
|
{
|
||||||
|
new PerformanceScore { Id = 3, ProductId = 2, TestType = "Single-Core", Score = 1400 },
|
||||||
|
new PerformanceScore { Id = 4, ProductId = 2, TestType = "Multi-Core", Score = 7500 }
|
||||||
|
},
|
||||||
|
Specifications = new List<Specification>
|
||||||
|
{
|
||||||
|
new Specification { Id = 3, ProductId = 2, Name = "Cores", Value = "8" },
|
||||||
|
new Specification { Id = 4, ProductId = 2, Name = "Threads", Value = "16" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_mockProductRepository.Setup(repo => repo.GetByIdsAsync(productIds))
|
||||||
|
.ReturnsAsync(products);
|
||||||
|
|
||||||
|
_mockMapper.Setup(m => m.Map<List<ProductDto>>(products))
|
||||||
|
.Returns(productDtos);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _comparisonService.CompareProductsAsync(productIds);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(2, result.Products.Count);
|
||||||
|
Assert.NotNull(result.ComparisonMatrix);
|
||||||
|
_mockProductRepository.Verify(repo => repo.GetByIdsAsync(productIds), Times.Once);
|
||||||
|
_mockMapper.Verify(m => m.Map<List<ProductDto>>(products), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CompareProductsAsync_EmptyProductIds_ThrowsArgumentException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var productIds = new List<int>();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsAsync<ArgumentException>(async () =>
|
||||||
|
await _comparisonService.CompareProductsAsync(productIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CompareProductsAsync_TooManyProductIds_ThrowsArgumentException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var productIds = new List<int> { 1, 2, 3, 4, 5 };
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsAsync<ArgumentException>(async () =>
|
||||||
|
await _comparisonService.CompareProductsAsync(productIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CompareProductsAsync_NonExistingProductIds_ThrowsKeyNotFoundException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var productIds = new List<int> { 1, 2 };
|
||||||
|
|
||||||
|
_mockProductRepository.Setup(repo => repo.GetByIdsAsync(productIds))
|
||||||
|
.ReturnsAsync(new List<Product>());
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsAsync<KeyNotFoundException>(async () =>
|
||||||
|
await _comparisonService.CompareProductsAsync(productIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
184
HardwarePerformance.Tests/Services/ProductServiceTests.cs
Normal file
184
HardwarePerformance.Tests/Services/ProductServiceTests.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using HardwarePerformance.Models;
|
||||||
|
using HardwarePerformance.Models.DTOs;
|
||||||
|
using HardwarePerformance.Services;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Tests.Services
|
||||||
|
{
|
||||||
|
public class ProductServiceTests
|
||||||
|
{
|
||||||
|
private readonly Mock<IProductRepository> _mockProductRepository;
|
||||||
|
private readonly Mock<IMapper> _mockMapper;
|
||||||
|
private readonly ProductService _productService;
|
||||||
|
|
||||||
|
public ProductServiceTests()
|
||||||
|
{
|
||||||
|
_mockProductRepository = new Mock<IProductRepository>();
|
||||||
|
_mockMapper = new Mock<IMapper>();
|
||||||
|
_productService = new ProductService(_mockProductRepository.Object, _mockMapper.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetProductsByCategoryAsync_ReturnsPagedProducts()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var categoryId = 1;
|
||||||
|
var page = 1;
|
||||||
|
var pageSize = 10;
|
||||||
|
var sortBy = "Name";
|
||||||
|
var sortOrder = "asc";
|
||||||
|
|
||||||
|
var products = new List<Product>
|
||||||
|
{
|
||||||
|
new Product { Id = 1, Name = "Intel Core i9", CategoryId = categoryId },
|
||||||
|
new Product { Id = 2, Name = "AMD Ryzen 9", CategoryId = categoryId }
|
||||||
|
};
|
||||||
|
|
||||||
|
var productDtos = new List<ProductListDto>
|
||||||
|
{
|
||||||
|
new ProductListDto { Id = 1, Name = "Intel Core i9" },
|
||||||
|
new ProductListDto { Id = 2, Name = "AMD Ryzen 9" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var pagedResult = new PagedResultDto<ProductListDto>
|
||||||
|
{
|
||||||
|
Items = productDtos,
|
||||||
|
TotalCount = 2,
|
||||||
|
Page = page,
|
||||||
|
PageSize = pageSize
|
||||||
|
};
|
||||||
|
|
||||||
|
_mockProductRepository.Setup(repo => repo.GetByCategoryAsync(categoryId, page, pageSize, sortBy, sortOrder))
|
||||||
|
.ReturnsAsync(products);
|
||||||
|
|
||||||
|
_mockProductRepository.Setup(repo => repo.CountAsync(categoryId))
|
||||||
|
.ReturnsAsync(2);
|
||||||
|
|
||||||
|
_mockMapper.Setup(m => m.Map<IEnumerable<ProductListDto>>(products))
|
||||||
|
.Returns(productDtos);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _productService.GetProductsByCategoryAsync(categoryId, page, pageSize, sortBy, sortOrder);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(2, result.TotalCount);
|
||||||
|
Assert.Equal(2, result.Items.Count());
|
||||||
|
_mockProductRepository.Verify(repo => repo.GetByCategoryAsync(categoryId, page, pageSize, sortBy, sortOrder), Times.Once);
|
||||||
|
_mockProductRepository.Verify(repo => repo.CountAsync(categoryId), Times.Once);
|
||||||
|
_mockMapper.Verify(m => m.Map<IEnumerable<ProductListDto>>(products), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetProductByIdAsync_ExistingProduct_ReturnsProductDto()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var productId = 1;
|
||||||
|
var product = new Product
|
||||||
|
{
|
||||||
|
Id = productId,
|
||||||
|
Name = "Intel Core i9",
|
||||||
|
CategoryId = 1,
|
||||||
|
PerformanceScores = new List<PerformanceScore>(),
|
||||||
|
Specifications = new List<Specification>()
|
||||||
|
};
|
||||||
|
|
||||||
|
var productDto = new ProductDto
|
||||||
|
{
|
||||||
|
Id = productId,
|
||||||
|
Name = "Intel Core i9",
|
||||||
|
CategoryId = 1,
|
||||||
|
PerformanceScores = new List<PerformanceScore>(),
|
||||||
|
Specifications = new List<Specification>()
|
||||||
|
};
|
||||||
|
|
||||||
|
_mockProductRepository.Setup(repo => repo.GetByIdAsync(productId))
|
||||||
|
.ReturnsAsync(product);
|
||||||
|
|
||||||
|
_mockMapper.Setup(m => m.Map<ProductDto>(product))
|
||||||
|
.Returns(productDto);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _productService.GetProductByIdAsync(productId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(productId, result.Id);
|
||||||
|
Assert.Equal("Intel Core i9", result.Name);
|
||||||
|
_mockProductRepository.Verify(repo => repo.GetByIdAsync(productId), Times.Once);
|
||||||
|
_mockMapper.Verify(m => m.Map<ProductDto>(product), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetProductByIdAsync_NonExistingProduct_ReturnsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var productId = 999;
|
||||||
|
|
||||||
|
_mockProductRepository.Setup(repo => repo.GetByIdAsync(productId))
|
||||||
|
.ReturnsAsync((Product?)null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _productService.GetProductByIdAsync(productId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(result);
|
||||||
|
_mockProductRepository.Verify(repo => repo.GetByIdAsync(productId), Times.Once);
|
||||||
|
_mockMapper.Verify(m => m.Map<ProductDto>(It.IsAny<Product>()), Times.Never);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SearchProductsAsync_ReturnsPagedSearchResults()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var query = "Intel";
|
||||||
|
var categoryId = 1;
|
||||||
|
var manufacturer = "Intel";
|
||||||
|
var minScore = 1000;
|
||||||
|
var maxScore = 5000;
|
||||||
|
var page = 1;
|
||||||
|
var pageSize = 10;
|
||||||
|
|
||||||
|
var products = new List<Product>
|
||||||
|
{
|
||||||
|
new Product { Id = 1, Name = "Intel Core i9", Manufacturer = "Intel", CategoryId = categoryId, PerformanceScore = 4000 },
|
||||||
|
new Product { Id = 2, Name = "Intel Core i7", Manufacturer = "Intel", CategoryId = categoryId, PerformanceScore = 3000 }
|
||||||
|
};
|
||||||
|
|
||||||
|
var productDtos = new List<ProductListDto>
|
||||||
|
{
|
||||||
|
new ProductListDto { Id = 1, Name = "Intel Core i9" },
|
||||||
|
new ProductListDto { Id = 2, Name = "Intel Core i7" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var pagedResult = new PagedResultDto<ProductListDto>
|
||||||
|
{
|
||||||
|
Items = productDtos,
|
||||||
|
TotalCount = 2,
|
||||||
|
Page = page,
|
||||||
|
PageSize = pageSize
|
||||||
|
};
|
||||||
|
|
||||||
|
_mockProductRepository.Setup(repo => repo.SearchAsync(query, categoryId, manufacturer, minScore, maxScore, page, pageSize))
|
||||||
|
.ReturnsAsync(products);
|
||||||
|
|
||||||
|
_mockProductRepository.Setup(repo => repo.CountSearchResultsAsync(query, categoryId, manufacturer, minScore, maxScore))
|
||||||
|
.ReturnsAsync(2);
|
||||||
|
|
||||||
|
_mockMapper.Setup(m => m.Map<IEnumerable<ProductListDto>>(products))
|
||||||
|
.Returns(productDtos);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _productService.SearchProductsAsync(query, categoryId, manufacturer, minScore, maxScore, page, pageSize);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Equal(2, result.TotalCount);
|
||||||
|
Assert.Equal(2, result.Items.Count());
|
||||||
|
_mockProductRepository.Verify(repo => repo.SearchAsync(query, categoryId, manufacturer, minScore, maxScore, page, pageSize), Times.Once);
|
||||||
|
_mockProductRepository.Verify(repo => repo.CountSearchResultsAsync(query, categoryId, manufacturer, minScore, maxScore), Times.Once);
|
||||||
|
_mockMapper.Verify(m => m.Map<IEnumerable<ProductListDto>>(products), Times.Once);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
HardwarePerformance.Tests/UnitTest1.cs
Normal file
10
HardwarePerformance.Tests/UnitTest1.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace HardwarePerformance.Tests;
|
||||||
|
|
||||||
|
public class UnitTest1
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Test1()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"format": 1,
|
||||||
|
"restore": {
|
||||||
|
"C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj": {}
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"projectName": "HardwarePerformance.Tests",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\代\\.nuget\\packages\\",
|
||||||
|
"outputPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"fallbackFolders": [
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||||
|
],
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\代\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net9.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||||
|
"https://api.nuget.org/v3/index.json": {},
|
||||||
|
"https://nuget.cdn.azure.cn/v3/index.json": {},
|
||||||
|
"https://packages.chinacloudapi.cn/v3/index.json": {},
|
||||||
|
"https://packages.microsoft.com/dotnet": {},
|
||||||
|
"https://www.nuget.org/api/v2/": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"restoreAuditProperties": {
|
||||||
|
"enableAudit": "true",
|
||||||
|
"auditLevel": "low",
|
||||||
|
"auditMode": "direct"
|
||||||
|
},
|
||||||
|
"SdkAnalysisLevel": "9.0.300"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NET.Test.Sdk": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[17.12.0, )"
|
||||||
|
},
|
||||||
|
"coverlet.collector": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[6.0.2, )"
|
||||||
|
},
|
||||||
|
"xunit": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[2.9.2, )"
|
||||||
|
},
|
||||||
|
"xunit.runner.visualstudio": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[2.8.2, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||||
|
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||||
|
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||||
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\代\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.0</NuGetToolVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<SourceRoot Include="C:\Users\代\.nuget\packages\" />
|
||||||
|
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||||
126
HardwarePerformance.Tests/obj/project.assets.json
Normal file
126
HardwarePerformance.Tests/obj/project.assets.json
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"targets": {
|
||||||
|
"net9.0": {}
|
||||||
|
},
|
||||||
|
"libraries": {},
|
||||||
|
"projectFileDependencyGroups": {
|
||||||
|
"net9.0": [
|
||||||
|
"Microsoft.NET.Test.Sdk >= 17.12.0",
|
||||||
|
"coverlet.collector >= 6.0.2",
|
||||||
|
"xunit >= 2.9.2",
|
||||||
|
"xunit.runner.visualstudio >= 2.8.2"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"packageFolders": {
|
||||||
|
"C:\\Users\\代\\.nuget\\packages\\": {},
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"projectName": "HardwarePerformance.Tests",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\代\\.nuget\\packages\\",
|
||||||
|
"outputPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"fallbackFolders": [
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||||
|
],
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\代\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net9.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||||
|
"https://api.nuget.org/v3/index.json": {},
|
||||||
|
"https://nuget.cdn.azure.cn/v3/index.json": {},
|
||||||
|
"https://packages.chinacloudapi.cn/v3/index.json": {},
|
||||||
|
"https://packages.microsoft.com/dotnet": {},
|
||||||
|
"https://www.nuget.org/api/v2/": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"restoreAuditProperties": {
|
||||||
|
"enableAudit": "true",
|
||||||
|
"auditLevel": "low",
|
||||||
|
"auditMode": "direct"
|
||||||
|
},
|
||||||
|
"SdkAnalysisLevel": "9.0.300"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NET.Test.Sdk": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[17.12.0, )"
|
||||||
|
},
|
||||||
|
"coverlet.collector": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[6.0.2, )"
|
||||||
|
},
|
||||||
|
"xunit": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[2.9.2, )"
|
||||||
|
},
|
||||||
|
"xunit.runner.visualstudio": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[2.8.2, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"logs": [
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='coverlet.collector'&semVerLevel=2.0.0”检索有关“coverlet.collector”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"libraryId": "coverlet.collector"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='xunit'&semVerLevel=2.0.0”检索有关“xunit”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"libraryId": "xunit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NET.Test.Sdk'&semVerLevel=2.0.0”检索有关“Microsoft.NET.Test.Sdk”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"libraryId": "Microsoft.NET.Test.Sdk"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
36
HardwarePerformance.Tests/obj/project.nuget.cache
Normal file
36
HardwarePerformance.Tests/obj/project.nuget.cache
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"dgSpecHash": "HWf5d7t+LFg=",
|
||||||
|
"success": false,
|
||||||
|
"projectFilePath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"expectedPackageFiles": [],
|
||||||
|
"logs": [
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='coverlet.collector'&semVerLevel=2.0.0”检索有关“coverlet.collector”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"filePath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"libraryId": "coverlet.collector",
|
||||||
|
"targetGraphs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='xunit'&semVerLevel=2.0.0”检索有关“xunit”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"filePath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"libraryId": "xunit",
|
||||||
|
"targetGraphs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NET.Test.Sdk'&semVerLevel=2.0.0”检索有关“Microsoft.NET.Test.Sdk”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"filePath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
|
||||||
|
"libraryId": "Microsoft.NET.Test.Sdk",
|
||||||
|
"targetGraphs": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
20
MinimalAPI/MappingProfile.cs
Normal file
20
MinimalAPI/MappingProfile.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using HardwarePerformance.Models;
|
||||||
|
using HardwarePerformance.Models.DTOs;
|
||||||
|
|
||||||
|
namespace HardwarePerformance
|
||||||
|
{
|
||||||
|
public class MappingProfile : Profile
|
||||||
|
{
|
||||||
|
public MappingProfile()
|
||||||
|
{
|
||||||
|
CreateMap<Category, CategoryDto>();
|
||||||
|
|
||||||
|
CreateMap<Product, ProductDto>()
|
||||||
|
.ForMember(dest => dest.PerformanceScores, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.Specifications, opt => opt.Ignore());
|
||||||
|
|
||||||
|
CreateMap<Product, ProductListDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
MinimalAPI/MinimalAPI.csproj
Normal file
13
MinimalAPI/MinimalAPI.csproj
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
9
MinimalAPI/Models/DTOs/CategoryDto.cs
Normal file
9
MinimalAPI/Models/DTOs/CategoryDto.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace HardwarePerformance.Models.DTOs
|
||||||
|
{
|
||||||
|
public class CategoryDto
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
MinimalAPI/Models/DTOs/PagedResultDto.cs
Normal file
11
MinimalAPI/Models/DTOs/PagedResultDto.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace HardwarePerformance.Models.DTOs
|
||||||
|
{
|
||||||
|
public class PagedResultDto<T>
|
||||||
|
{
|
||||||
|
public List<T> Items { get; set; } = new();
|
||||||
|
public int Total { get; set; }
|
||||||
|
public int CurrentPage { get; set; }
|
||||||
|
public int PageSize { get; set; }
|
||||||
|
public int TotalPages { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
20
MinimalAPI/Models/DTOs/ProductDto.cs
Normal file
20
MinimalAPI/Models/DTOs/ProductDto.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Models.DTOs
|
||||||
|
{
|
||||||
|
public class ProductDto
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Model { get; set; } = string.Empty;
|
||||||
|
public string Manufacturer { get; set; } = string.Empty;
|
||||||
|
public int CategoryId { get; set; }
|
||||||
|
public int CurrentRank { get; set; }
|
||||||
|
public DateTime ReleaseDate { get; set; }
|
||||||
|
public decimal? Price { get; set; }
|
||||||
|
public int? PerformanceScore { get; set; }
|
||||||
|
public CategoryDto? Category { get; set; }
|
||||||
|
public List<PerformanceScore> PerformanceScores { get; set; } = new();
|
||||||
|
public List<Specification> Specifications { get; set; } = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
MinimalAPI/Models/DTOs/ProductListDto.cs
Normal file
15
MinimalAPI/Models/DTOs/ProductListDto.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace HardwarePerformance.Models.DTOs
|
||||||
|
{
|
||||||
|
public class ProductListDto
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Model { get; set; } = string.Empty;
|
||||||
|
public string Manufacturer { get; set; } = string.Empty;
|
||||||
|
public int CategoryId { get; set; }
|
||||||
|
public int CurrentRank { get; set; }
|
||||||
|
public DateTime ReleaseDate { get; set; }
|
||||||
|
public decimal? Price { get; set; }
|
||||||
|
public int? PerformanceScore { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
184
MinimalAPI/Program.cs
Normal file
184
MinimalAPI/Program.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace MinimalAPI
|
||||||
|
{
|
||||||
|
// 定义数据模型
|
||||||
|
record Category(int Id, string Name, string Description);
|
||||||
|
record Product(int Id, string Name, string Model, string Manufacturer, int CategoryId, int CurrentRank, DateTime ReleaseDate, decimal? Price);
|
||||||
|
record ApiResponse<T>(bool Success, T? Data, string? Message = null);
|
||||||
|
record PagedResponse<T>(List<T> Items, int TotalCount, int PageNumber, int PageSize, int TotalPages);
|
||||||
|
record ComparisonRequest(List<int> ProductIds);
|
||||||
|
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// 配置响应压缩
|
||||||
|
builder.Services.AddResponseCompression(options =>
|
||||||
|
{
|
||||||
|
options.EnableForHttps = true;
|
||||||
|
options.Providers.Add<BrotliCompressionProvider>();
|
||||||
|
options.Providers.Add<GzipCompressionProvider>();
|
||||||
|
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
|
||||||
|
{
|
||||||
|
"application/json",
|
||||||
|
"application/javascript",
|
||||||
|
"text/css",
|
||||||
|
"text/html",
|
||||||
|
"text/plain",
|
||||||
|
"text/xml"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
|
||||||
|
{
|
||||||
|
options.Level = CompressionLevel.Fastest;
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.Configure<GzipCompressionProviderOptions>(options =>
|
||||||
|
{
|
||||||
|
options.Level = CompressionLevel.Fastest;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 配置JSON序列化选项
|
||||||
|
builder.Services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options =>
|
||||||
|
{
|
||||||
|
options.SerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase;
|
||||||
|
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||||
|
});
|
||||||
|
|
||||||
|
// 配置CORS
|
||||||
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("AllowAll", policy =>
|
||||||
|
{
|
||||||
|
policy.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 注册服务
|
||||||
|
builder.Services.AddScoped<ICategoryService, CategoryService>();
|
||||||
|
builder.Services.AddScoped<IProductService, ProductService>();
|
||||||
|
builder.Services.AddScoped<IComparisonService, ComparisonService>();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// 添加响应压缩中间件
|
||||||
|
app.UseResponseCompression();
|
||||||
|
|
||||||
|
// 使用CORS
|
||||||
|
app.UseCors("AllowAll");
|
||||||
|
|
||||||
|
// 模拟数据
|
||||||
|
var categories = new List<Category>
|
||||||
|
{
|
||||||
|
new(1, "手机CPU", "移动设备处理器"),
|
||||||
|
new(2, "手机GPU", "移动设备图形处理器"),
|
||||||
|
new(3, "电脑CPU", "桌面和笔记本处理器"),
|
||||||
|
new(4, "电脑GPU", "桌面和笔记本图形处理器")
|
||||||
|
};
|
||||||
|
|
||||||
|
var products = new List<Product>
|
||||||
|
{
|
||||||
|
new(1, "Apple A17 Pro", "A17 Pro", "Apple", 1, 1, new DateTime(2023, 9, 12), null),
|
||||||
|
new(2, "Snapdragon 8 Gen 3", "SM8650-AB", "Qualcomm", 1, 2, new DateTime(2023, 10, 24), null),
|
||||||
|
new(3, "Intel Core i9-13900K", "Core i9-13900K", "Intel", 3, 1, new DateTime(2022, 10, 20), 589.99m),
|
||||||
|
new(4, "AMD Ryzen 9 7950X", "Ryzen 9 7950X", "AMD", 3, 2, new DateTime(2022, 9, 27), 699.99m),
|
||||||
|
new(5, "NVIDIA GeForce RTX 4090", "RTX 4090", "NVIDIA", 4, 1, new DateTime(2022, 10, 12), 1599.99m),
|
||||||
|
new(6, "AMD Radeon RX 7900 XTX", "RX 7900 XTX", "AMD", 4, 2, new DateTime(2022, 12, 3), 999.99m)
|
||||||
|
};
|
||||||
|
|
||||||
|
// API端点
|
||||||
|
|
||||||
|
// 类别相关
|
||||||
|
app.MapGet("/api/categories", async (ICategoryService categoryService) =>
|
||||||
|
{
|
||||||
|
var categories = await categoryService.GetAllCategoriesAsync();
|
||||||
|
return Results.Ok(new ApiResponse<List<CategoryDto>>(true, categories));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/categories/{id}", async (int id, ICategoryService categoryService) =>
|
||||||
|
{
|
||||||
|
var category = await categoryService.GetCategoryByIdAsync(id);
|
||||||
|
if (category == null)
|
||||||
|
{
|
||||||
|
return Results.NotFound(new ApiResponse<object>(false, null, "类别不存在"));
|
||||||
|
}
|
||||||
|
return Results.Ok(new ApiResponse<CategoryDto>(true, category));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 产品API
|
||||||
|
app.MapGet("/api/products", async (int? categoryId, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string sortOrder = "asc", IProductService productService) =>
|
||||||
|
{
|
||||||
|
if (!categoryId.HasValue)
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new ApiResponse<object>(false, null, "类别ID是必需的"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var pagedResult = await productService.GetProductsByCategoryAsync(categoryId.Value, page, pageSize, sortBy, sortOrder);
|
||||||
|
return Results.Ok(new ApiResponse<PagedResultDto<ProductListDto>>(true, pagedResult));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/products/{id}", async (int id, IProductService productService) =>
|
||||||
|
{
|
||||||
|
var product = await productService.GetProductByIdAsync(id);
|
||||||
|
if (product == null)
|
||||||
|
{
|
||||||
|
return Results.NotFound(new ApiResponse<object>(false, null, "产品不存在"));
|
||||||
|
}
|
||||||
|
return Results.Ok(new ApiResponse<ProductDto>(true, product));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/products/search", async (string q, int? categoryId, string? manufacturer, decimal? minScore, decimal? maxScore, int page = 1, int pageSize = 20, IProductService productService) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(q))
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new ApiResponse<object>(false, null, "搜索关键词不能为空"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var pagedResult = await productService.SearchProductsAsync(q, categoryId, manufacturer, minScore, maxScore, page, pageSize);
|
||||||
|
return Results.Ok(new ApiResponse<PagedResultDto<ProductListDto>>(true, pagedResult));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/products/filter", async (int categoryId, string? manufacturer, decimal? minScore, decimal? maxScore, int? year, int page = 1, int pageSize = 20, IProductService productService) =>
|
||||||
|
{
|
||||||
|
var pagedResult = await productService.FilterProductsAsync(categoryId, manufacturer, minScore, maxScore, year, page, pageSize);
|
||||||
|
return Results.Ok(new ApiResponse<PagedResultDto<ProductListDto>>(true, pagedResult));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 产品对比
|
||||||
|
app.MapPost("/api/comparison", async (ComparisonRequest request, IComparisonService comparisonService) =>
|
||||||
|
{
|
||||||
|
// 验证请求
|
||||||
|
if (request.ProductIds == null || request.ProductIds.Count < 2 || request.ProductIds.Count > 4)
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new ApiResponse<object>(false, null, "产品ID数量必须在2到4之间"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var comparisonData = await comparisonService.CompareProductsAsync(request.ProductIds);
|
||||||
|
if (comparisonData == null)
|
||||||
|
{
|
||||||
|
return Results.NotFound(new ApiResponse<object>(false, null, "无法获取产品对比数据"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results.Ok(new ApiResponse<object>(true, comparisonData));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 状态检查端点
|
||||||
|
app.MapGet("/api/status", () => new
|
||||||
|
{
|
||||||
|
Status = "Running",
|
||||||
|
Message = "API服务正常运行",
|
||||||
|
Timestamp = DateTime.Now,
|
||||||
|
Version = "1.0.0"
|
||||||
|
});
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
MinimalAPI/Properties/launchSettings.json
Normal file
23
MinimalAPI/Properties/launchSettings.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "http://localhost:5172",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "https://localhost:7055;http://localhost:5172",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
MinimalAPI/Repositories/CategoryRepository.cs
Normal file
28
MinimalAPI/Repositories/CategoryRepository.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using HardwarePerformance.Data;
|
||||||
|
using HardwarePerformance.Models;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Repositories
|
||||||
|
{
|
||||||
|
public class CategoryRepository : Repository<Category>, ICategoryRepository
|
||||||
|
{
|
||||||
|
public CategoryRepository(AppDbContext context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Category?> GetByNameAsync(string name)
|
||||||
|
{
|
||||||
|
return await _dbSet.FirstOrDefaultAsync(c => c.Name == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ExistsAsync(int id)
|
||||||
|
{
|
||||||
|
return await _dbSet.AnyAsync(c => c.Id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> NameExistsAsync(string name)
|
||||||
|
{
|
||||||
|
return await _dbSet.AnyAsync(c => c.Name == name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
MinimalAPI/Repositories/ICategoryRepository.cs
Normal file
11
MinimalAPI/Repositories/ICategoryRepository.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using HardwarePerformance.Models;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Repositories
|
||||||
|
{
|
||||||
|
public interface ICategoryRepository : IRepository<Category>
|
||||||
|
{
|
||||||
|
Task<Category?> GetByNameAsync(string name);
|
||||||
|
Task<bool> ExistsAsync(int id);
|
||||||
|
Task<bool> NameExistsAsync(string name);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
MinimalAPI/Repositories/IProductRepository.cs
Normal file
18
MinimalAPI/Repositories/IProductRepository.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using HardwarePerformance.Models;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Repositories
|
||||||
|
{
|
||||||
|
public interface IProductRepository : IRepository<Product>
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Product>> GetByCategoryAsync(int categoryId);
|
||||||
|
Task<IEnumerable<Product>> GetByCategoryAsync(int categoryId, int page, int pageSize, string sortBy = "CurrentRank", string sortOrder = "asc");
|
||||||
|
Task<IEnumerable<Product>> SearchAsync(string query);
|
||||||
|
Task<IEnumerable<Product>> SearchAsync(string query, int? categoryId = null, string? manufacturer = null, int? minScore = null, int? maxScore = null, int page = 1, int pageSize = 20);
|
||||||
|
Task<IEnumerable<Product>> FilterAsync(int? categoryId, string? manufacturer, int? minScore, int? maxScore, int? year);
|
||||||
|
Task<IEnumerable<Product>> FilterAsync(int? categoryId, string? manufacturer, int? minScore, int? maxScore, int? year, int page, int pageSize, string sortBy = "CurrentRank", string sortOrder = "asc");
|
||||||
|
Task<int> CountAsync(int? categoryId = null);
|
||||||
|
Task<int> CountSearchResultsAsync(string query, int? categoryId = null, string? manufacturer = null, int? minScore = null, int? maxScore = null);
|
||||||
|
Task<int> CountFilterResultsAsync(int? categoryId, string? manufacturer, int? minScore, int? maxScore, int? year);
|
||||||
|
Task<Category?> GetCategoryByProductIdAsync(int productId);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
MinimalAPI/Repositories/IRepository.cs
Normal file
16
MinimalAPI/Repositories/IRepository.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using HardwarePerformance.Models;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Repositories
|
||||||
|
{
|
||||||
|
public interface IRepository<T> where T : class
|
||||||
|
{
|
||||||
|
Task<T?> GetByIdAsync(int id);
|
||||||
|
Task<IEnumerable<T>> GetAllAsync();
|
||||||
|
Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> predicate);
|
||||||
|
Task<T> AddAsync(T entity);
|
||||||
|
Task UpdateAsync(T entity);
|
||||||
|
Task DeleteAsync(T entity);
|
||||||
|
Task<int> CountAsync(Expression<Func<T, bool>>? predicate = null);
|
||||||
|
}
|
||||||
|
}
|
||||||
265
MinimalAPI/Repositories/ProductRepository.cs
Normal file
265
MinimalAPI/Repositories/ProductRepository.cs
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using HardwarePerformance.Data;
|
||||||
|
using HardwarePerformance.Models;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Repositories
|
||||||
|
{
|
||||||
|
public class ProductRepository : Repository<Product>, IProductRepository
|
||||||
|
{
|
||||||
|
public ProductRepository(AppDbContext context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Product>> GetByCategoryAsync(int categoryId)
|
||||||
|
{
|
||||||
|
return await _dbSet
|
||||||
|
.Where(p => p.CategoryId == categoryId)
|
||||||
|
.OrderBy(p => p.CurrentRank)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Product>> GetByCategoryAsync(int categoryId, int page, int pageSize, string sortBy = "CurrentRank", string sortOrder = "asc")
|
||||||
|
{
|
||||||
|
var query = _dbSet.Where(p => p.CategoryId == categoryId);
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
query = sortBy.ToLower() switch
|
||||||
|
{
|
||||||
|
"name" => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.Name) : query.OrderBy(p => p.Name),
|
||||||
|
"manufacturer" => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.Manufacturer) : query.OrderBy(p => p.Manufacturer),
|
||||||
|
"releasedate" => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.ReleaseDate) : query.OrderBy(p => p.ReleaseDate),
|
||||||
|
"price" => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.Price) : query.OrderBy(p => p.Price),
|
||||||
|
_ => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.CurrentRank) : query.OrderBy(p => p.CurrentRank)
|
||||||
|
};
|
||||||
|
|
||||||
|
return await query
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Product>> SearchAsync(string query)
|
||||||
|
{
|
||||||
|
return await _dbSet
|
||||||
|
.Where(p =>
|
||||||
|
p.Name.Contains(query) ||
|
||||||
|
p.Model.Contains(query) ||
|
||||||
|
p.Manufacturer.Contains(query))
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Product>> SearchAsync(string query, int? categoryId = null, string? manufacturer = null, int? minScore = null, int? maxScore = null, int page = 1, int pageSize = 20)
|
||||||
|
{
|
||||||
|
var queryable = _dbSet.AsQueryable();
|
||||||
|
|
||||||
|
if (categoryId.HasValue)
|
||||||
|
{
|
||||||
|
queryable = queryable.Where(p => p.CategoryId == categoryId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(manufacturer))
|
||||||
|
{
|
||||||
|
queryable = queryable.Where(p => p.Manufacturer == manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
queryable = queryable.Where(p => (100 - p.CurrentRank) >= minScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
queryable = queryable.Where(p => (100 - p.CurrentRank) <= maxScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(query))
|
||||||
|
{
|
||||||
|
queryable = queryable.Where(p =>
|
||||||
|
p.Name.Contains(query) ||
|
||||||
|
p.Model.Contains(query) ||
|
||||||
|
p.Manufacturer.Contains(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
return await queryable
|
||||||
|
.OrderBy(p => p.CurrentRank)
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Product>> FilterAsync(int? categoryId, string? manufacturer, int? minScore, int? maxScore, int? year)
|
||||||
|
{
|
||||||
|
var query = _dbSet.AsQueryable();
|
||||||
|
|
||||||
|
if (categoryId.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.CategoryId == categoryId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(manufacturer))
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.Manufacturer == manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
query = query.Where(p => (100 - p.CurrentRank) >= minScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
query = query.Where(p => (100 - p.CurrentRank) <= maxScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (year.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.ReleaseDate.Year == year.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await query.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Product>> FilterAsync(int? categoryId, string? manufacturer, int? minScore, int? maxScore, int? year, int page, int pageSize, string sortBy = "CurrentRank", string sortOrder = "asc")
|
||||||
|
{
|
||||||
|
var query = _dbSet.AsQueryable();
|
||||||
|
|
||||||
|
if (categoryId.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.CategoryId == categoryId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(manufacturer))
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.Manufacturer == manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
query = query.Where(p => (100 - p.CurrentRank) >= minScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
query = query.Where(p => (100 - p.CurrentRank) <= maxScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (year.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.ReleaseDate.Year == year.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
query = sortBy.ToLower() switch
|
||||||
|
{
|
||||||
|
"name" => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.Name) : query.OrderBy(p => p.Name),
|
||||||
|
"manufacturer" => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.Manufacturer) : query.OrderBy(p => p.Manufacturer),
|
||||||
|
"releasedate" => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.ReleaseDate) : query.OrderBy(p => p.ReleaseDate),
|
||||||
|
"price" => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.Price) : query.OrderBy(p => p.Price),
|
||||||
|
_ => sortOrder.ToLower() == "desc" ? query.OrderByDescending(p => p.CurrentRank) : query.OrderBy(p => p.CurrentRank)
|
||||||
|
};
|
||||||
|
|
||||||
|
return await query
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> CountAsync(int? categoryId = null)
|
||||||
|
{
|
||||||
|
var query = _dbSet.AsQueryable();
|
||||||
|
|
||||||
|
if (categoryId.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.CategoryId == categoryId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await query.CountAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> CountSearchResultsAsync(string query, int? categoryId = null, string? manufacturer = null, int? minScore = null, int? maxScore = null)
|
||||||
|
{
|
||||||
|
var queryable = _dbSet.AsQueryable();
|
||||||
|
|
||||||
|
if (categoryId.HasValue)
|
||||||
|
{
|
||||||
|
queryable = queryable.Where(p => p.CategoryId == categoryId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(manufacturer))
|
||||||
|
{
|
||||||
|
queryable = queryable.Where(p => p.Manufacturer == manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
queryable = queryable.Where(p => (100 - p.CurrentRank) >= minScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
queryable = queryable.Where(p => (100 - p.CurrentRank) <= maxScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(query))
|
||||||
|
{
|
||||||
|
queryable = queryable.Where(p =>
|
||||||
|
p.Name.Contains(query) ||
|
||||||
|
p.Model.Contains(query) ||
|
||||||
|
p.Manufacturer.Contains(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
return await queryable.CountAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> CountFilterResultsAsync(int? categoryId, string? manufacturer, int? minScore, int? maxScore, int? year)
|
||||||
|
{
|
||||||
|
var query = _dbSet.AsQueryable();
|
||||||
|
|
||||||
|
if (categoryId.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.CategoryId == categoryId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(manufacturer))
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.Manufacturer == manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
query = query.Where(p => (100 - p.CurrentRank) >= minScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScore.HasValue)
|
||||||
|
{
|
||||||
|
// 使用排名计算性能分数(100 - 排名)
|
||||||
|
query = query.Where(p => (100 - p.CurrentRank) <= maxScore.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (year.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.ReleaseDate.Year == year.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await query.CountAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Category?> GetCategoryByProductIdAsync(int productId)
|
||||||
|
{
|
||||||
|
var product = await _dbSet
|
||||||
|
.Include(p => p.Category)
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == productId);
|
||||||
|
|
||||||
|
return product?.Category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
MinimalAPI/Repositories/Repository.cs
Normal file
60
MinimalAPI/Repositories/Repository.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using HardwarePerformance.Data;
|
||||||
|
using HardwarePerformance.Models;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Repositories
|
||||||
|
{
|
||||||
|
public class Repository<T> : IRepository<T> where T : class
|
||||||
|
{
|
||||||
|
protected readonly AppDbContext _context;
|
||||||
|
protected readonly DbSet<T> _dbSet;
|
||||||
|
|
||||||
|
public Repository(AppDbContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_dbSet = context.Set<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<T?> GetByIdAsync(int id)
|
||||||
|
{
|
||||||
|
return await _dbSet.FindAsync(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<T>> GetAllAsync()
|
||||||
|
{
|
||||||
|
return await _dbSet.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> predicate)
|
||||||
|
{
|
||||||
|
return await _dbSet.Where(predicate).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<T> AddAsync(T entity)
|
||||||
|
{
|
||||||
|
await _dbSet.AddAsync(entity);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAsync(T entity)
|
||||||
|
{
|
||||||
|
_dbSet.Update(entity);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAsync(T entity)
|
||||||
|
{
|
||||||
|
_dbSet.Remove(entity);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> CountAsync(Expression<Func<T, bool>>? predicate = null)
|
||||||
|
{
|
||||||
|
if (predicate == null)
|
||||||
|
return await _dbSet.CountAsync();
|
||||||
|
return await _dbSet.CountAsync(predicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
MinimalAPI/Services/CategoryService.cs
Normal file
30
MinimalAPI/Services/CategoryService.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using HardwarePerformance.Models.DTOs;
|
||||||
|
using HardwarePerformance.Repositories;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Services
|
||||||
|
{
|
||||||
|
public class CategoryService : ICategoryService
|
||||||
|
{
|
||||||
|
private readonly ICategoryRepository _categoryRepository;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public CategoryService(ICategoryRepository categoryRepository, IMapper mapper)
|
||||||
|
{
|
||||||
|
_categoryRepository = categoryRepository;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<CategoryDto>> GetAllCategoriesAsync()
|
||||||
|
{
|
||||||
|
var categories = await _categoryRepository.GetAllAsync();
|
||||||
|
return _mapper.Map<IEnumerable<CategoryDto>>(categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CategoryDto?> GetCategoryByIdAsync(int id)
|
||||||
|
{
|
||||||
|
var category = await _categoryRepository.GetByIdAsync(id);
|
||||||
|
return category != null ? _mapper.Map<CategoryDto>(category) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
271
MinimalAPI/Services/ComparisonService.cs
Normal file
271
MinimalAPI/Services/ComparisonService.cs
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using MinimalAPI.Data;
|
||||||
|
using MinimalAPI.Models;
|
||||||
|
using MinimalAPI.Models.DTOs;
|
||||||
|
|
||||||
|
namespace MinimalAPI.Services
|
||||||
|
{
|
||||||
|
public class ComparisonService : IComparisonService
|
||||||
|
{
|
||||||
|
private readonly AppDbContext _context;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public ComparisonService(AppDbContext context, IMapper mapper)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<object> CompareProductsAsync(List<int> productIds)
|
||||||
|
{
|
||||||
|
// 验证输入
|
||||||
|
if (productIds == null || productIds.Count < 2 || productIds.Count > 4)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取产品
|
||||||
|
var products = await _context.Products
|
||||||
|
.Include(p => p.Category)
|
||||||
|
.Where(p => productIds.Contains(p.Id))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (products.Count != productIds.Count)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否所有产品属于同一类别
|
||||||
|
var categoryIds = products.Select(p => p.CategoryId).Distinct().ToList();
|
||||||
|
if (categoryIds.Count > 1)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取性能分数
|
||||||
|
var productIdsList = products.Select(p => p.Id).ToList();
|
||||||
|
var performanceScores = await _context.PerformanceScores
|
||||||
|
.Where(ps => productIdsList.Contains(ps.ProductId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 获取规格参数
|
||||||
|
var specifications = await _context.Specifications
|
||||||
|
.Where(s => productIdsList.Contains(s.ProductId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 创建产品DTO列表
|
||||||
|
var productDtos = products.Select(p => {
|
||||||
|
var dto = _mapper.Map<ProductDto>(p);
|
||||||
|
dto.PerformanceScores = performanceScores
|
||||||
|
.Where(ps => ps.ProductId == p.Id)
|
||||||
|
.ToList();
|
||||||
|
dto.Specifications = specifications
|
||||||
|
.Where(s => s.ProductId == p.Id)
|
||||||
|
.ToList();
|
||||||
|
return dto;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// 生成对比矩阵
|
||||||
|
var comparisonMatrix = GenerateComparisonMatrix(productDtos);
|
||||||
|
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
Products = productDtos,
|
||||||
|
Comparison = comparisonMatrix
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Dictionary<string, object>> GenerateComparisonMatrix(List<ProductDto> products)
|
||||||
|
{
|
||||||
|
var matrix = new List<Dictionary<string, object>>();
|
||||||
|
|
||||||
|
// 添加基本信息行
|
||||||
|
matrix.Add(new Dictionary<string, object> { ["指标"] = "产品名称", ["类型"] = "基本信息" });
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
matrix[0][$"{product.Name}"] = product.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加制造商行
|
||||||
|
matrix.Add(new Dictionary<string, object> { ["指标"] = "制造商", ["类型"] = "基本信息" });
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
matrix[1][$"{product.Name}"] = product.Manufacturer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加型号行
|
||||||
|
matrix.Add(new Dictionary<string, object> { ["指标"] = "型号", ["类型"] = "基本信息" });
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
matrix[2][$"{product.Name}"] = product.Model;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加排名行
|
||||||
|
matrix.Add(new Dictionary<string, object> { ["指标"] = "当前排名", ["类型"] = "性能指标" });
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
matrix[3][$"{product.Name}"] = product.CurrentRank;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加发布日期行
|
||||||
|
matrix.Add(new Dictionary<string, object> { ["指标"] = "发布日期", ["类型"] = "基本信息" });
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
matrix[4][$"{product.Name}"] = product.ReleaseDate.ToString("yyyy-MM-dd");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加价格行
|
||||||
|
matrix.Add(new Dictionary<string, object> { ["指标"] = "价格", ["类型"] = "基本信息" });
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
matrix[5][$"{product.Name}"] = product.Price?.ToString("C") ?? "N/A";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加性能分数行
|
||||||
|
var benchmarkTypes = products
|
||||||
|
.SelectMany(p => p.PerformanceScores)
|
||||||
|
.Select(ps => ps.BenchmarkType)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var benchmarkType in benchmarkTypes)
|
||||||
|
{
|
||||||
|
var rowIndex = matrix.Count;
|
||||||
|
matrix.Add(new Dictionary<string, object> { ["指标"] = benchmarkType, ["类型"] = "性能指标" });
|
||||||
|
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
var score = product.PerformanceScores
|
||||||
|
.FirstOrDefault(ps => ps.BenchmarkType == benchmarkType)?.Score;
|
||||||
|
matrix[rowIndex][$"{product.Name}"] = score?.ToString() ?? "N/A";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加规格参数行
|
||||||
|
var specNames = products
|
||||||
|
.SelectMany(p => p.Specifications)
|
||||||
|
.Select(s => s.Name)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var specName in specNames)
|
||||||
|
{
|
||||||
|
var rowIndex = matrix.Count;
|
||||||
|
matrix.Add(new Dictionary<string, object> { ["指标"] = specName, ["类型"] = "规格参数" });
|
||||||
|
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
var specValue = product.Specifications
|
||||||
|
.FirstOrDefault(s => s.Name == specName)?.Value;
|
||||||
|
matrix[rowIndex][$"{product.Name}"] = specValue ?? "N/A";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记最优和最差值
|
||||||
|
MarkBestAndWorstValues(matrix, products);
|
||||||
|
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MarkBestAndWorstValues(List<Dictionary<string, object>> matrix, List<ProductDto> products)
|
||||||
|
{
|
||||||
|
// 对于排名,越小越好
|
||||||
|
var rankRow = matrix.FirstOrDefault(m => m["指标"].ToString() == "当前排名");
|
||||||
|
if (rankRow != null)
|
||||||
|
{
|
||||||
|
var ranks = products.Select(p => p.CurrentRank).ToList();
|
||||||
|
var minRank = ranks.Min();
|
||||||
|
var maxRank = ranks.Max();
|
||||||
|
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
var rank = product.CurrentRank;
|
||||||
|
if (rank == minRank)
|
||||||
|
{
|
||||||
|
rankRow[$"{product.Name}_isBest"] = true;
|
||||||
|
}
|
||||||
|
else if (rank == maxRank)
|
||||||
|
{
|
||||||
|
rankRow[$"{product.Name}_isWorst"] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于价格,越小越好
|
||||||
|
var priceRow = matrix.FirstOrDefault(m => m["指标"].ToString() == "价格");
|
||||||
|
if (priceRow != null)
|
||||||
|
{
|
||||||
|
var prices = products.Where(p => p.Price.HasValue).Select(p => p.Price!.Value).ToList();
|
||||||
|
if (prices.Any())
|
||||||
|
{
|
||||||
|
var minPrice = prices.Min();
|
||||||
|
var maxPrice = prices.Max();
|
||||||
|
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
if (product.Price.HasValue)
|
||||||
|
{
|
||||||
|
if (product.Price == minPrice)
|
||||||
|
{
|
||||||
|
priceRow[$"{product.Name}_isBest"] = true;
|
||||||
|
}
|
||||||
|
else if (product.Price == maxPrice)
|
||||||
|
{
|
||||||
|
priceRow[$"{product.Name}_isWorst"] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于性能分数,越大越好
|
||||||
|
var performanceRows = matrix.Where(m => m["类型"].ToString() == "性能指标" &&
|
||||||
|
m["指标"].ToString() != "当前排名").ToList();
|
||||||
|
|
||||||
|
foreach (var row in performanceRows)
|
||||||
|
{
|
||||||
|
var benchmarkType = row["指标"].ToString();
|
||||||
|
var scores = new List<decimal?>();
|
||||||
|
|
||||||
|
foreach (var product in products)
|
||||||
|
{
|
||||||
|
var scoreStr = row[$"{product.Name}"]?.ToString();
|
||||||
|
if (decimal.TryParse(scoreStr, out var score))
|
||||||
|
{
|
||||||
|
scores.Add(score);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scores.Add(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var validScores = scores.Where(s => s.HasValue).Select(s => s!.Value).ToList();
|
||||||
|
if (validScores.Any())
|
||||||
|
{
|
||||||
|
var maxScore = validScores.Max();
|
||||||
|
var minScore = validScores.Min();
|
||||||
|
|
||||||
|
for (int i = 0; i < products.Count; i++)
|
||||||
|
{
|
||||||
|
if (scores[i].HasValue)
|
||||||
|
{
|
||||||
|
if (scores[i] == maxScore)
|
||||||
|
{
|
||||||
|
row[$"{products[i].Name}_isBest"] = true;
|
||||||
|
}
|
||||||
|
else if (scores[i] == minScore)
|
||||||
|
{
|
||||||
|
row[$"{products[i].Name}_isWorst"] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
MinimalAPI/Services/ICategoryService.cs
Normal file
10
MinimalAPI/Services/ICategoryService.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using HardwarePerformance.Models.DTOs;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Services
|
||||||
|
{
|
||||||
|
public interface ICategoryService
|
||||||
|
{
|
||||||
|
Task<IEnumerable<CategoryDto>> GetAllCategoriesAsync();
|
||||||
|
Task<CategoryDto?> GetCategoryByIdAsync(int id);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
MinimalAPI/Services/IComparisonService.cs
Normal file
10
MinimalAPI/Services/IComparisonService.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MinimalAPI.Services
|
||||||
|
{
|
||||||
|
public interface IComparisonService
|
||||||
|
{
|
||||||
|
Task<object> CompareProductsAsync(List<int> productIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
MinimalAPI/Services/IProductService.cs
Normal file
12
MinimalAPI/Services/IProductService.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using HardwarePerformance.Models.DTOs;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Services
|
||||||
|
{
|
||||||
|
public interface IProductService
|
||||||
|
{
|
||||||
|
Task<PagedResultDto<ProductListDto>> GetProductsByCategoryAsync(int categoryId, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string order = "asc");
|
||||||
|
Task<ProductDto?> GetProductByIdAsync(int id);
|
||||||
|
Task<PagedResultDto<ProductListDto>> SearchProductsAsync(string query, int? categoryId = null, string? manufacturer = null, int? minScore = null, int? maxScore = null, int page = 1, int pageSize = 20);
|
||||||
|
Task<PagedResultDto<ProductListDto>> FilterProductsAsync(int categoryId, string? manufacturer = null, int? minScore = null, int? maxScore = null, int? releaseYear = null, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string order = "asc");
|
||||||
|
}
|
||||||
|
}
|
||||||
91
MinimalAPI/Services/ProductService.cs
Normal file
91
MinimalAPI/Services/ProductService.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using HardwarePerformance.Models.DTOs;
|
||||||
|
using HardwarePerformance.Repositories;
|
||||||
|
|
||||||
|
namespace HardwarePerformance.Services
|
||||||
|
{
|
||||||
|
public class ProductService : IProductService
|
||||||
|
{
|
||||||
|
private readonly IProductRepository _productRepository;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public ProductService(IProductRepository productRepository, IMapper mapper)
|
||||||
|
{
|
||||||
|
_productRepository = productRepository;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PagedResultDto<ProductListDto>> GetProductsByCategoryAsync(int categoryId, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string order = "asc")
|
||||||
|
{
|
||||||
|
var products = await _productRepository.GetByCategoryAsync(categoryId, page, pageSize, sortBy, order);
|
||||||
|
var totalCount = await _productRepository.CountAsync(categoryId);
|
||||||
|
|
||||||
|
var productDtos = _mapper.Map<IEnumerable<ProductListDto>>(products);
|
||||||
|
|
||||||
|
return new PagedResultDto<ProductListDto>
|
||||||
|
{
|
||||||
|
Items = productDtos.ToList(),
|
||||||
|
Total = totalCount,
|
||||||
|
CurrentPage = page,
|
||||||
|
PageSize = pageSize,
|
||||||
|
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ProductDto?> GetProductByIdAsync(int id)
|
||||||
|
{
|
||||||
|
var product = await _productRepository.GetByIdAsync(id);
|
||||||
|
if (product == null) return null;
|
||||||
|
|
||||||
|
var productDto = _mapper.Map<ProductDto>(product);
|
||||||
|
|
||||||
|
// 获取类别信息
|
||||||
|
var category = await _productRepository.GetCategoryByProductIdAsync(id);
|
||||||
|
if (category != null)
|
||||||
|
{
|
||||||
|
productDto.Category = new CategoryDto
|
||||||
|
{
|
||||||
|
Id = category.Id,
|
||||||
|
Name = category.Name,
|
||||||
|
Description = category.Description
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return productDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PagedResultDto<ProductListDto>> SearchProductsAsync(string query, int? categoryId = null, string? manufacturer = null, int? minScore = null, int? maxScore = null, int page = 1, int pageSize = 20)
|
||||||
|
{
|
||||||
|
var products = await _productRepository.SearchAsync(query, categoryId, manufacturer, minScore, maxScore, page, pageSize);
|
||||||
|
var totalCount = await _productRepository.CountSearchResultsAsync(query, categoryId, manufacturer, minScore, maxScore);
|
||||||
|
|
||||||
|
var productDtos = _mapper.Map<IEnumerable<ProductListDto>>(products);
|
||||||
|
|
||||||
|
return new PagedResultDto<ProductListDto>
|
||||||
|
{
|
||||||
|
Items = productDtos.ToList(),
|
||||||
|
Total = totalCount,
|
||||||
|
CurrentPage = page,
|
||||||
|
PageSize = pageSize,
|
||||||
|
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PagedResultDto<ProductListDto>> FilterProductsAsync(int categoryId, string? manufacturer = null, int? minScore = null, int? maxScore = null, int? releaseYear = null, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string order = "asc")
|
||||||
|
{
|
||||||
|
var products = await _productRepository.FilterAsync(categoryId, manufacturer, minScore, maxScore, releaseYear, page, pageSize, sortBy, order);
|
||||||
|
var totalCount = await _productRepository.CountFilterResultsAsync(categoryId, manufacturer, minScore, maxScore, releaseYear);
|
||||||
|
|
||||||
|
var productDtos = _mapper.Map<IEnumerable<ProductListDto>>(products);
|
||||||
|
|
||||||
|
return new PagedResultDto<ProductListDto>
|
||||||
|
{
|
||||||
|
Items = productDtos.ToList(),
|
||||||
|
Total = totalCount,
|
||||||
|
CurrentPage = page,
|
||||||
|
PageSize = pageSize,
|
||||||
|
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
MinimalAPI/appsettings.Development.json
Normal file
8
MinimalAPI/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
MinimalAPI/appsettings.json
Normal file
9
MinimalAPI/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
23
MinimalAPI/bin/Debug/net9.0/MinimalAPI.deps.json
Normal file
23
MinimalAPI/bin/Debug/net9.0/MinimalAPI.deps.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v9.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v9.0": {
|
||||||
|
"MinimalAPI/1.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"MinimalAPI.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"MinimalAPI/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
MinimalAPI/bin/Debug/net9.0/MinimalAPI.dll
Normal file
BIN
MinimalAPI/bin/Debug/net9.0/MinimalAPI.dll
Normal file
Binary file not shown.
BIN
MinimalAPI/bin/Debug/net9.0/MinimalAPI.exe
Normal file
BIN
MinimalAPI/bin/Debug/net9.0/MinimalAPI.exe
Normal file
Binary file not shown.
BIN
MinimalAPI/bin/Debug/net9.0/MinimalAPI.pdb
Normal file
BIN
MinimalAPI/bin/Debug/net9.0/MinimalAPI.pdb
Normal file
Binary file not shown.
19
MinimalAPI/bin/Debug/net9.0/MinimalAPI.runtimeconfig.json
Normal file
19
MinimalAPI/bin/Debug/net9.0/MinimalAPI.runtimeconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"runtimeOptions": {
|
||||||
|
"tfm": "net9.0",
|
||||||
|
"frameworks": [
|
||||||
|
{
|
||||||
|
"name": "Microsoft.NETCore.App",
|
||||||
|
"version": "9.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft.AspNetCore.App",
|
||||||
|
"version": "9.0.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configProperties": {
|
||||||
|
"System.GC.Server": true,
|
||||||
|
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"Version":1,"ManifestType":"Build","Endpoints":[]}
|
||||||
8
MinimalAPI/bin/Debug/net9.0/appsettings.Development.json
Normal file
8
MinimalAPI/bin/Debug/net9.0/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
MinimalAPI/bin/Debug/net9.0/appsettings.json
Normal file
9
MinimalAPI/bin/Debug/net9.0/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// <autogenerated />
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0")]
|
||||||
22
MinimalAPI/obj/Debug/net9.0/MinimalAPI.AssemblyInfo.cs
Normal file
22
MinimalAPI/obj/Debug/net9.0/MinimalAPI.AssemblyInfo.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
[assembly: System.Reflection.AssemblyCompanyAttribute("MinimalAPI")]
|
||||||
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyProductAttribute("MinimalAPI")]
|
||||||
|
[assembly: System.Reflection.AssemblyTitleAttribute("MinimalAPI")]
|
||||||
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|
||||||
|
// 由 MSBuild WriteCodeFragment 类生成。
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
d440d87b19ec785d73e3e23306ab9680f7c4890517e977a1c254363c4f9347af
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
is_global = true
|
||||||
|
build_property.TargetFramework = net9.0
|
||||||
|
build_property.TargetPlatformMinVersion =
|
||||||
|
build_property.UsingMicrosoftNETSdkWeb = true
|
||||||
|
build_property.ProjectTypeGuids =
|
||||||
|
build_property.InvariantGlobalization =
|
||||||
|
build_property.PlatformNeutralAssembly =
|
||||||
|
build_property.EnforceExtendedAnalyzerRules =
|
||||||
|
build_property._SupportedPlatformList = Linux,macOS,Windows
|
||||||
|
build_property.RootNamespace = MinimalAPI
|
||||||
|
build_property.RootNamespace = MinimalAPI
|
||||||
|
build_property.ProjectDir = C:\work\电脑硬件-01\MinimalAPI\
|
||||||
|
build_property.EnableComHosting =
|
||||||
|
build_property.EnableGeneratedComInterfaceComImportInterop =
|
||||||
|
build_property.RazorLangVersion = 9.0
|
||||||
|
build_property.SupportLocalizedComponentNames =
|
||||||
|
build_property.GenerateRazorMetadataSourceChecksumAttributes =
|
||||||
|
build_property.MSBuildProjectDirectory = C:\work\电脑硬件-01\MinimalAPI
|
||||||
|
build_property._RazorSourceGeneratorDebug =
|
||||||
|
build_property.EffectiveAnalysisLevelStyle = 9.0
|
||||||
|
build_property.EnableCodeStyleSeverity =
|
||||||
17
MinimalAPI/obj/Debug/net9.0/MinimalAPI.GlobalUsings.g.cs
Normal file
17
MinimalAPI/obj/Debug/net9.0/MinimalAPI.GlobalUsings.g.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// <auto-generated/>
|
||||||
|
global using global::Microsoft.AspNetCore.Builder;
|
||||||
|
global using global::Microsoft.AspNetCore.Hosting;
|
||||||
|
global using global::Microsoft.AspNetCore.Http;
|
||||||
|
global using global::Microsoft.AspNetCore.Routing;
|
||||||
|
global using global::Microsoft.Extensions.Configuration;
|
||||||
|
global using global::Microsoft.Extensions.DependencyInjection;
|
||||||
|
global using global::Microsoft.Extensions.Hosting;
|
||||||
|
global using global::Microsoft.Extensions.Logging;
|
||||||
|
global using global::System;
|
||||||
|
global using global::System.Collections.Generic;
|
||||||
|
global using global::System.IO;
|
||||||
|
global using global::System.Linq;
|
||||||
|
global using global::System.Net.Http;
|
||||||
|
global using global::System.Net.Http.Json;
|
||||||
|
global using global::System.Threading;
|
||||||
|
global using global::System.Threading.Tasks;
|
||||||
BIN
MinimalAPI/obj/Debug/net9.0/MinimalAPI.assets.cache
Normal file
BIN
MinimalAPI/obj/Debug/net9.0/MinimalAPI.assets.cache
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
05c277f9ef6d1c96b7c3a0662bb97967ee23e63c93d8aa1cd4aec40fc1c9febe
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\rpswa.dswa.cache.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\MinimalAPI.GeneratedMSBuildEditorConfig.editorconfig
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\MinimalAPI.AssemblyInfoInputs.cache
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\MinimalAPI.AssemblyInfo.cs
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\MinimalAPI.csproj.CoreCompileInputs.cache
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\MinimalAPI.MvcApplicationPartsAssemblyInfo.cache
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\bin\Debug\net9.0\appsettings.Development.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\bin\Debug\net9.0\appsettings.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\bin\Debug\net9.0\MinimalAPI.staticwebassets.endpoints.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\bin\Debug\net9.0\MinimalAPI.exe
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\bin\Debug\net9.0\MinimalAPI.deps.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\bin\Debug\net9.0\MinimalAPI.runtimeconfig.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\bin\Debug\net9.0\MinimalAPI.dll
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\bin\Debug\net9.0\MinimalAPI.pdb
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\rjimswa.dswa.cache.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\rjsmrazor.dswa.cache.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\rjsmcshtml.dswa.cache.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\scopedcss\bundle\MinimalAPI.styles.css
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\staticwebassets.build.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\staticwebassets.build.json.cache
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\staticwebassets.development.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\staticwebassets.build.endpoints.json
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\MinimalAPI.dll
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\refint\MinimalAPI.dll
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\MinimalAPI.pdb
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\MinimalAPI.genruntimeconfig.cache
|
||||||
|
C:\work\电脑硬件-01\MinimalAPI\obj\Debug\net9.0\ref\MinimalAPI.dll
|
||||||
BIN
MinimalAPI/obj/Debug/net9.0/MinimalAPI.dll
Normal file
BIN
MinimalAPI/obj/Debug/net9.0/MinimalAPI.dll
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
2cc508c4c984e00de0cee28ea5f00a982100be8dad563e9011ff5619c65193f1
|
||||||
BIN
MinimalAPI/obj/Debug/net9.0/MinimalAPI.pdb
Normal file
BIN
MinimalAPI/obj/Debug/net9.0/MinimalAPI.pdb
Normal file
Binary file not shown.
BIN
MinimalAPI/obj/Debug/net9.0/apphost.exe
Normal file
BIN
MinimalAPI/obj/Debug/net9.0/apphost.exe
Normal file
Binary file not shown.
BIN
MinimalAPI/obj/Debug/net9.0/ref/MinimalAPI.dll
Normal file
BIN
MinimalAPI/obj/Debug/net9.0/ref/MinimalAPI.dll
Normal file
Binary file not shown.
BIN
MinimalAPI/obj/Debug/net9.0/refint/MinimalAPI.dll
Normal file
BIN
MinimalAPI/obj/Debug/net9.0/refint/MinimalAPI.dll
Normal file
Binary file not shown.
1
MinimalAPI/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json
Normal file
1
MinimalAPI/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"GlobalPropertiesHash":"UvHx1BUBnfpFc6gxIpp/8mxp/Pr5ugj++Q4ag8rCqAY=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["vICfSWyJTl7Llwoo5pZeHmuInfb\u002BPDuiEXf67e03aVY=","HGCAjAUzY86/cTTfeLk8LuqAnP1lIVdvBKQP\u002BJ23JAc=","pXPB2q0SLSiqgQ6QWxaK7/r8KBQLxQCCriy2hCwae1A=","eZ0avPpvDZzkkkg3Y40\u002B9/FcOts1TlMSAvHEIAFbU8Q="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||||
1
MinimalAPI/obj/Debug/net9.0/rjsmrazor.dswa.cache.json
Normal file
1
MinimalAPI/obj/Debug/net9.0/rjsmrazor.dswa.cache.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"GlobalPropertiesHash":"N05q42TiGbCpQThCMeppx1cqHYMYPr+MKOVECH+LM5o=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["vICfSWyJTl7Llwoo5pZeHmuInfb\u002BPDuiEXf67e03aVY=","HGCAjAUzY86/cTTfeLk8LuqAnP1lIVdvBKQP\u002BJ23JAc=","pXPB2q0SLSiqgQ6QWxaK7/r8KBQLxQCCriy2hCwae1A=","eZ0avPpvDZzkkkg3Y40\u002B9/FcOts1TlMSAvHEIAFbU8Q="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||||
1
MinimalAPI/obj/Debug/net9.0/rpswa.dswa.cache.json
Normal file
1
MinimalAPI/obj/Debug/net9.0/rpswa.dswa.cache.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"GlobalPropertiesHash":"Qscza4zuOZL6qExaAaOGJZbKXeiSjSngMQ6k1ALDEr8=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["vICfSWyJTl7Llwoo5pZeHmuInfb\u002BPDuiEXf67e03aVY=","HGCAjAUzY86/cTTfeLk8LuqAnP1lIVdvBKQP\u002BJ23JAc="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"Version":1,"ManifestType":"Build","Endpoints":[]}
|
||||||
1
MinimalAPI/obj/Debug/net9.0/staticwebassets.build.json
Normal file
1
MinimalAPI/obj/Debug/net9.0/staticwebassets.build.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"Version":1,"Hash":"JkTLtN583la2vWjETk7JpCURqkzL9J5tTWuu+nxCKow=","Source":"MinimalAPI","BasePath":"_content/MinimalAPI","Mode":"Default","ManifestType":"Build","ReferencedProjectsConfiguration":[],"DiscoveryPatterns":[],"Assets":[],"Endpoints":[]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
JkTLtN583la2vWjETk7JpCURqkzL9J5tTWuu+nxCKow=
|
||||||
86
MinimalAPI/obj/MinimalAPI.csproj.nuget.dgspec.json
Normal file
86
MinimalAPI/obj/MinimalAPI.csproj.nuget.dgspec.json
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"format": 1,
|
||||||
|
"restore": {
|
||||||
|
"C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj": {}
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj",
|
||||||
|
"projectName": "MinimalAPI",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\代\\.nuget\\packages\\",
|
||||||
|
"outputPath": "C:\\work\\电脑硬件-01\\MinimalAPI\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"fallbackFolders": [
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||||
|
],
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\代\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net9.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||||
|
"https://api.nuget.org/v3/index.json": {},
|
||||||
|
"https://nuget.cdn.azure.cn/v3/index.json": {},
|
||||||
|
"https://packages.chinacloudapi.cn/v3/index.json": {},
|
||||||
|
"https://packages.microsoft.com/dotnet": {},
|
||||||
|
"https://www.nuget.org/api/v2/": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"restoreAuditProperties": {
|
||||||
|
"enableAudit": "true",
|
||||||
|
"auditLevel": "low",
|
||||||
|
"auditMode": "direct"
|
||||||
|
},
|
||||||
|
"SdkAnalysisLevel": "9.0.300"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNetCore.ResponseCompression": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[2.2.0, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.AspNetCore.App": {
|
||||||
|
"privateAssets": "none"
|
||||||
|
},
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
MinimalAPI/obj/MinimalAPI.csproj.nuget.g.props
Normal file
16
MinimalAPI/obj/MinimalAPI.csproj.nuget.g.props
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||||
|
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||||
|
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||||
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\代\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.0</NuGetToolVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<SourceRoot Include="C:\Users\代\.nuget\packages\" />
|
||||||
|
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
2
MinimalAPI/obj/MinimalAPI.csproj.nuget.g.targets
Normal file
2
MinimalAPI/obj/MinimalAPI.csproj.nuget.g.targets
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||||
102
MinimalAPI/obj/project.assets.json
Normal file
102
MinimalAPI/obj/project.assets.json
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"targets": {
|
||||||
|
"net9.0": {}
|
||||||
|
},
|
||||||
|
"libraries": {},
|
||||||
|
"projectFileDependencyGroups": {
|
||||||
|
"net9.0": [
|
||||||
|
"Microsoft.AspNetCore.ResponseCompression >= 2.2.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"packageFolders": {
|
||||||
|
"C:\\Users\\代\\.nuget\\packages\\": {},
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj",
|
||||||
|
"projectName": "MinimalAPI",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\代\\.nuget\\packages\\",
|
||||||
|
"outputPath": "C:\\work\\电脑硬件-01\\MinimalAPI\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"fallbackFolders": [
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||||
|
],
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\代\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net9.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||||
|
"https://api.nuget.org/v3/index.json": {},
|
||||||
|
"https://nuget.cdn.azure.cn/v3/index.json": {},
|
||||||
|
"https://packages.chinacloudapi.cn/v3/index.json": {},
|
||||||
|
"https://packages.microsoft.com/dotnet": {},
|
||||||
|
"https://www.nuget.org/api/v2/": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"restoreAuditProperties": {
|
||||||
|
"enableAudit": "true",
|
||||||
|
"auditLevel": "low",
|
||||||
|
"auditMode": "direct"
|
||||||
|
},
|
||||||
|
"SdkAnalysisLevel": "9.0.300"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNetCore.ResponseCompression": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[2.2.0, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.AspNetCore.App": {
|
||||||
|
"privateAssets": "none"
|
||||||
|
},
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"logs": [
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.AspNetCore.ResponseCompression'&semVerLevel=2.0.0”检索有关“Microsoft.AspNetCore.ResponseCompression”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"libraryId": "Microsoft.AspNetCore.ResponseCompression"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
18
MinimalAPI/obj/project.nuget.cache
Normal file
18
MinimalAPI/obj/project.nuget.cache
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"dgSpecHash": "ionCG+ayp8g=",
|
||||||
|
"success": false,
|
||||||
|
"projectFilePath": "C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj",
|
||||||
|
"expectedPackageFiles": [],
|
||||||
|
"logs": [
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.AspNetCore.ResponseCompression'&semVerLevel=2.0.0”检索有关“Microsoft.AspNetCore.ResponseCompression”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj",
|
||||||
|
"filePath": "C:\\work\\电脑硬件-01\\MinimalAPI\\MinimalAPI.csproj",
|
||||||
|
"libraryId": "Microsoft.AspNetCore.ResponseCompression",
|
||||||
|
"targetGraphs": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
41
SimpleAPI/Program.cs
Normal file
41
SimpleAPI/Program.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Add services to the container.
|
||||||
|
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||||
|
builder.Services.AddOpenApi();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.MapOpenApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
var summaries = new[]
|
||||||
|
{
|
||||||
|
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||||
|
};
|
||||||
|
|
||||||
|
app.MapGet("/weatherforecast", () =>
|
||||||
|
{
|
||||||
|
var forecast = Enumerable.Range(1, 5).Select(index =>
|
||||||
|
new WeatherForecast
|
||||||
|
(
|
||||||
|
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
||||||
|
Random.Shared.Next(-20, 55),
|
||||||
|
summaries[Random.Shared.Next(summaries.Length)]
|
||||||
|
))
|
||||||
|
.ToArray();
|
||||||
|
return forecast;
|
||||||
|
})
|
||||||
|
.WithName("GetWeatherForecast");
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
|
||||||
|
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
|
||||||
|
{
|
||||||
|
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||||
|
}
|
||||||
23
SimpleAPI/Properties/launchSettings.json
Normal file
23
SimpleAPI/Properties/launchSettings.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"applicationUrl": "http://localhost:5256",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"applicationUrl": "https://localhost:7149;http://localhost:5256",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
SimpleAPI/SimpleAPI.csproj
Normal file
13
SimpleAPI/SimpleAPI.csproj
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.8" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
6
SimpleAPI/SimpleAPI.http
Normal file
6
SimpleAPI/SimpleAPI.http
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@SimpleAPI_HostAddress = http://localhost:5256
|
||||||
|
|
||||||
|
GET {{SimpleAPI_HostAddress}}/weatherforecast/
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
8
SimpleAPI/appsettings.Development.json
Normal file
8
SimpleAPI/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
SimpleAPI/appsettings.json
Normal file
9
SimpleAPI/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
86
SimpleAPI/obj/SimpleAPI.csproj.nuget.dgspec.json
Normal file
86
SimpleAPI/obj/SimpleAPI.csproj.nuget.dgspec.json
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"format": 1,
|
||||||
|
"restore": {
|
||||||
|
"C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj": {}
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"projectName": "SimpleAPI",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\代\\.nuget\\packages\\",
|
||||||
|
"outputPath": "C:\\work\\电脑硬件-01\\SimpleAPI\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"fallbackFolders": [
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||||
|
],
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\代\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net9.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||||
|
"https://api.nuget.org/v3/index.json": {},
|
||||||
|
"https://nuget.cdn.azure.cn/v3/index.json": {},
|
||||||
|
"https://packages.chinacloudapi.cn/v3/index.json": {},
|
||||||
|
"https://packages.microsoft.com/dotnet": {},
|
||||||
|
"https://www.nuget.org/api/v2/": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"restoreAuditProperties": {
|
||||||
|
"enableAudit": "true",
|
||||||
|
"auditLevel": "low",
|
||||||
|
"auditMode": "direct"
|
||||||
|
},
|
||||||
|
"SdkAnalysisLevel": "9.0.300"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNetCore.OpenApi": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[9.0.8, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.AspNetCore.App": {
|
||||||
|
"privateAssets": "none"
|
||||||
|
},
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
SimpleAPI/obj/SimpleAPI.csproj.nuget.g.props
Normal file
16
SimpleAPI/obj/SimpleAPI.csproj.nuget.g.props
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||||
|
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||||
|
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||||
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\代\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.0</NuGetToolVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<SourceRoot Include="C:\Users\代\.nuget\packages\" />
|
||||||
|
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
2
SimpleAPI/obj/SimpleAPI.csproj.nuget.g.targets
Normal file
2
SimpleAPI/obj/SimpleAPI.csproj.nuget.g.targets
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||||
108
SimpleAPI/obj/project.assets.json
Normal file
108
SimpleAPI/obj/project.assets.json
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"targets": {
|
||||||
|
"net9.0": {}
|
||||||
|
},
|
||||||
|
"libraries": {},
|
||||||
|
"projectFileDependencyGroups": {
|
||||||
|
"net9.0": [
|
||||||
|
"Microsoft.AspNetCore.OpenApi >= 9.0.8"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"packageFolders": {
|
||||||
|
"C:\\Users\\代\\.nuget\\packages\\": {},
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"projectName": "SimpleAPI",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\代\\.nuget\\packages\\",
|
||||||
|
"outputPath": "C:\\work\\电脑硬件-01\\SimpleAPI\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"fallbackFolders": [
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||||
|
],
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\代\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net9.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||||
|
"https://api.nuget.org/v3/index.json": {},
|
||||||
|
"https://nuget.cdn.azure.cn/v3/index.json": {},
|
||||||
|
"https://packages.chinacloudapi.cn/v3/index.json": {},
|
||||||
|
"https://packages.microsoft.com/dotnet": {},
|
||||||
|
"https://www.nuget.org/api/v2/": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"restoreAuditProperties": {
|
||||||
|
"enableAudit": "true",
|
||||||
|
"auditLevel": "low",
|
||||||
|
"auditMode": "direct"
|
||||||
|
},
|
||||||
|
"SdkAnalysisLevel": "9.0.300"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net9.0": {
|
||||||
|
"targetAlias": "net9.0",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNetCore.OpenApi": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[9.0.8, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.AspNetCore.App": {
|
||||||
|
"privateAssets": "none"
|
||||||
|
},
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"logs": [
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.AspNetCore.OpenApi'&semVerLevel=2.0.0”检索有关“Microsoft.AspNetCore.OpenApi”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"libraryId": "Microsoft.AspNetCore.OpenApi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://packages.microsoft.com/dotnet/FindPackagesById()?id='Microsoft.AspNetCore.OpenApi'&semVerLevel=2.0.0”检索有关“Microsoft.AspNetCore.OpenApi”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"libraryId": "Microsoft.AspNetCore.OpenApi"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
27
SimpleAPI/obj/project.nuget.cache
Normal file
27
SimpleAPI/obj/project.nuget.cache
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"dgSpecHash": "qHQETFOfcmo=",
|
||||||
|
"success": false,
|
||||||
|
"projectFilePath": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"expectedPackageFiles": [],
|
||||||
|
"logs": [
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.AspNetCore.OpenApi'&semVerLevel=2.0.0”检索有关“Microsoft.AspNetCore.OpenApi”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"filePath": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"libraryId": "Microsoft.AspNetCore.OpenApi",
|
||||||
|
"targetGraphs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "NU1301",
|
||||||
|
"level": "Error",
|
||||||
|
"message": "未能从远程源“https://packages.microsoft.com/dotnet/FindPackagesById()?id='Microsoft.AspNetCore.OpenApi'&semVerLevel=2.0.0”检索有关“Microsoft.AspNetCore.OpenApi”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
|
||||||
|
"projectPath": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"filePath": "C:\\work\\电脑硬件-01\\SimpleAPI\\SimpleAPI.csproj",
|
||||||
|
"libraryId": "Microsoft.AspNetCore.OpenApi",
|
||||||
|
"targetGraphs": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
471
TestAPI/Program.cs
Normal file
471
TestAPI/Program.cs
Normal file
@@ -0,0 +1,471 @@
|
|||||||
|
using Microsoft.AspNetCore.ResponseCompression;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// 添加响应压缩服务
|
||||||
|
builder.Services.AddResponseCompression(options =>
|
||||||
|
{
|
||||||
|
options.EnableForHttps = true;
|
||||||
|
options.Providers.Add<BrotliCompressionProvider>();
|
||||||
|
options.Providers.Add<GzipCompressionProvider>();
|
||||||
|
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/json" });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 配置压缩级别
|
||||||
|
builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
|
||||||
|
{
|
||||||
|
options.Level = CompressionLevel.Fastest;
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.Configure<GzipCompressionProviderOptions>(options =>
|
||||||
|
{
|
||||||
|
options.Level = CompressionLevel.Fastest;
|
||||||
|
});
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// 使用响应压缩中间件
|
||||||
|
app.UseResponseCompression();
|
||||||
|
|
||||||
|
// 添加一个返回大量数据的API端点,以便测试压缩效果
|
||||||
|
app.MapGet("/api/data", () => new
|
||||||
|
{
|
||||||
|
Message = "这是一个用于测试响应压缩的API端点",
|
||||||
|
Data = Enumerable.Range(1, 1000).Select(i => new { Id = i, Name = $"Item {i}", Description = $"这是第{i}个项目的描述,包含更多文本内容以便测试压缩效果。" }).ToArray(),
|
||||||
|
Timestamp = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加类别API端点,供前端测试使用
|
||||||
|
app.MapGet("/api/categories", () => new[]
|
||||||
|
{
|
||||||
|
new { Id = 1, Name = "手机CPU", Description = "移动设备处理器性能排名", ProductCount = 25 },
|
||||||
|
new { Id = 2, Name = "手机GPU", Description = "移动设备图形处理器性能排名", ProductCount = 18 },
|
||||||
|
new { Id = 3, Name = "电脑CPU", Description = "桌面处理器性能排名", ProductCount = 32 },
|
||||||
|
new { Id = 4, Name = "电脑GPU", Description = "桌面显卡性能排名", ProductCount = 28 }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加产品API端点,供前端测试使用
|
||||||
|
app.MapGet("/api/products", (int? categoryId, int page = 1, int pageSize = 20, string sortBy = "PerformanceScore", string order = "desc") =>
|
||||||
|
{
|
||||||
|
// 模拟产品数据
|
||||||
|
var allProducts = new[]
|
||||||
|
{
|
||||||
|
new { Id = 1, Name = "Snapdragon 8 Gen 2", Model = "SM8550-AB", Manufacturer = "Qualcomm", ReleaseYear = 2022, PerformanceScore = 3879, CurrentRank = 1, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 2, Name = "A16 Bionic", Model = "A16 Bionic", Manufacturer = "Apple", ReleaseYear = 2022, PerformanceScore = 3756, CurrentRank = 2, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 3, Name = "Dimensity 9200", Model = "MT6985", Manufacturer = "MediaTek", ReleaseYear = 2022, PerformanceScore = 3512, CurrentRank = 3, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 4, Name = "Snapdragon 8+ Gen 1", Model = "SM8475", Manufacturer = "Qualcomm", ReleaseYear = 2022, PerformanceScore = 3341, CurrentRank = 4, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 5, Name = "A15 Bionic", Model = "A15 Bionic", Manufacturer = "Apple", ReleaseYear = 2021, PerformanceScore = 3215, CurrentRank = 5, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 6, Name = "Adreno 740", Model = "Adreno 740", Manufacturer = "Qualcomm", ReleaseYear = 2022, PerformanceScore = 14350, CurrentRank = 1, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 7, Name = "Apple A16 GPU", Model = "A16 GPU", Manufacturer = "Apple", ReleaseYear = 2022, PerformanceScore = 13980, CurrentRank = 2, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 8, Name = "Mali-G715 MC10", Model = "Mali-G715", Manufacturer = "ARM", ReleaseYear = 2022, PerformanceScore = 12150, CurrentRank = 3, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 9, Name = "Adreno 730", Model = "Adreno 730", Manufacturer = "Qualcomm", ReleaseYear = 2022, PerformanceScore = 11020, CurrentRank = 4, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 10, Name = "Apple A15 GPU", Model = "A15 GPU", Manufacturer = "Apple", ReleaseYear = 2021, PerformanceScore = 10560, CurrentRank = 5, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 11, Name = "Intel Core i9-13900K", Model = "i9-13900K", Manufacturer = "Intel", ReleaseYear = 2022, PerformanceScore = 3176, CurrentRank = 1, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 12, Name = "AMD Ryzen 9 7950X", Model = "Ryzen 9 7950X", Manufacturer = "AMD", ReleaseYear = 2022, PerformanceScore = 3095, CurrentRank = 2, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 13, Name = "Intel Core i7-13700K", Model = "i7-13700K", Manufacturer = "Intel", ReleaseYear = 2022, PerformanceScore = 2956, CurrentRank = 3, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 14, Name = "AMD Ryzen 9 5900X", Model = "Ryzen 9 5900X", Manufacturer = "AMD", ReleaseYear = 2020, PerformanceScore = 2835, CurrentRank = 4, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 15, Name = "Intel Core i5-13600K", Model = "i5-13600K", Manufacturer = "Intel", ReleaseYear = 2022, PerformanceScore = 2742, CurrentRank = 5, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 16, Name = "NVIDIA GeForce RTX 4090", Model = "RTX 4090", Manufacturer = "NVIDIA", ReleaseYear = 2022, PerformanceScore = 38928, CurrentRank = 1, ImageUrl = "/images/placeholder.svg", CategoryId = 4 },
|
||||||
|
new { Id = 17, Name = "NVIDIA GeForce RTX 4080", Model = "RTX 4080", Manufacturer = "NVIDIA", ReleaseYear = 2022, PerformanceScore = 32168, CurrentRank = 2, ImageUrl = "/images/placeholder.svg", CategoryId = 4 },
|
||||||
|
new { Id = 18, Name = "NVIDIA GeForce RTX 3090 Ti", Model = "RTX 3090 Ti", Manufacturer = "NVIDIA", ReleaseYear = 2022, PerformanceScore = 28595, CurrentRank = 3, ImageUrl = "/images/placeholder.svg", CategoryId = 4 },
|
||||||
|
new { Id = 19, Name = "AMD Radeon RX 7900 XTX", Model = "RX 7900 XTX", Manufacturer = "AMD", ReleaseYear = 2022, PerformanceScore = 27850, CurrentRank = 4, ImageUrl = "/images/placeholder.svg", CategoryId = 4 },
|
||||||
|
new { Id = 20, Name = "NVIDIA GeForce RTX 3090", Model = "RTX 3090", Manufacturer = "NVIDIA", ReleaseYear = 2020, PerformanceScore = 26420, CurrentRank = 5, ImageUrl = "/images/placeholder.svg", CategoryId = 4 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据类别ID筛选
|
||||||
|
var filteredProducts = categoryId.HasValue
|
||||||
|
? allProducts.Where(p => p.CategoryId == categoryId.Value).ToArray()
|
||||||
|
: allProducts;
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
filteredProducts = sortBy.ToLower() switch
|
||||||
|
{
|
||||||
|
"name" => order.ToLower() == "desc"
|
||||||
|
? filteredProducts.OrderByDescending(p => p.Name).ToArray()
|
||||||
|
: filteredProducts.OrderBy(p => p.Name).ToArray(),
|
||||||
|
"manufacturer" => order.ToLower() == "desc"
|
||||||
|
? filteredProducts.OrderByDescending(p => p.Manufacturer).ToArray()
|
||||||
|
: filteredProducts.OrderBy(p => p.Manufacturer).ToArray(),
|
||||||
|
"releaseyear" => order.ToLower() == "desc"
|
||||||
|
? filteredProducts.OrderByDescending(p => p.ReleaseYear).ToArray()
|
||||||
|
: filteredProducts.OrderBy(p => p.ReleaseYear).ToArray(),
|
||||||
|
_ => order.ToLower() == "desc"
|
||||||
|
? filteredProducts.OrderByDescending(p => p.PerformanceScore).ToArray()
|
||||||
|
: filteredProducts.OrderBy(p => p.PerformanceScore).ToArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
var totalItems = filteredProducts.Length;
|
||||||
|
var totalPages = (int)Math.Ceiling((double)totalItems / pageSize);
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
var pagedProducts = filteredProducts
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return new {
|
||||||
|
Items = pagedProducts,
|
||||||
|
Total = totalItems,
|
||||||
|
CurrentPage = page,
|
||||||
|
PageSize = pageSize,
|
||||||
|
TotalPages = totalPages
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加产品详情API端点
|
||||||
|
app.MapGet("/api/products/{id}", (int id) =>
|
||||||
|
{
|
||||||
|
// 模拟产品详情数据
|
||||||
|
var allProducts = new[]
|
||||||
|
{
|
||||||
|
new {
|
||||||
|
Id = 1,
|
||||||
|
Name = "Snapdragon 8 Gen 2",
|
||||||
|
Model = "SM8550-AB",
|
||||||
|
Manufacturer = "Qualcomm",
|
||||||
|
ReleaseYear = 2022,
|
||||||
|
PerformanceScore = 3879,
|
||||||
|
CurrentRank = 1,
|
||||||
|
ImageUrl = "/images/placeholder.svg",
|
||||||
|
CategoryId = 1,
|
||||||
|
Description = "高通骁龙8 Gen 2是2022年推出的旗舰移动处理器,采用4nm工艺制程。",
|
||||||
|
Specifications = new[] {
|
||||||
|
new { Name = "工艺", Value = "4nm" },
|
||||||
|
new { Name = "核心数", Value = "8" },
|
||||||
|
new { Name = "主频", Value = "3.2GHz" },
|
||||||
|
new { Name = "GPU", Value = "Adreno 740" }
|
||||||
|
},
|
||||||
|
PerformanceScores = new[] {
|
||||||
|
new { Benchmark = "Geekbench 5 Single-Core", Score = 1524 },
|
||||||
|
new { Benchmark = "Geekbench 5 Multi-Core", Score = 5352 },
|
||||||
|
new { Benchmark = "AnTuTu 9", Score = 1314582 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
Id = 2,
|
||||||
|
Name = "A16 Bionic",
|
||||||
|
Model = "A16 Bionic",
|
||||||
|
Manufacturer = "Apple",
|
||||||
|
ReleaseYear = 2022,
|
||||||
|
PerformanceScore = 3756,
|
||||||
|
CurrentRank = 2,
|
||||||
|
ImageUrl = "/images/placeholder.svg",
|
||||||
|
CategoryId = 1,
|
||||||
|
Description = "苹果A16 Bionic是2022年推出的移动处理器,采用4nm工艺制程。",
|
||||||
|
Specifications = new[] {
|
||||||
|
new { Name = "工艺", Value = "4nm" },
|
||||||
|
new { Name = "核心数", Value = "6" },
|
||||||
|
new { Name = "主频", Value = "3.46GHz" },
|
||||||
|
new { Name = "GPU", Value = "Apple A16 GPU" }
|
||||||
|
},
|
||||||
|
PerformanceScores = new[] {
|
||||||
|
new { Benchmark = "Geekbench 5 Single-Core", Score = 1874 },
|
||||||
|
new { Benchmark = "Geekbench 5 Multi-Core", Score = 5372 },
|
||||||
|
new { Benchmark = "AnTuTu 9", Score = 1425876 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
Id = 3,
|
||||||
|
Name = "Dimensity 9200",
|
||||||
|
Model = "MT6985",
|
||||||
|
Manufacturer = "MediaTek",
|
||||||
|
ReleaseYear = 2022,
|
||||||
|
PerformanceScore = 3512,
|
||||||
|
CurrentRank = 3,
|
||||||
|
ImageUrl = "/images/placeholder.svg",
|
||||||
|
CategoryId = 1,
|
||||||
|
Description = "联发科天玑9200是2022年推出的旗舰移动处理器,采用4nm工艺制程。",
|
||||||
|
Specifications = new[] {
|
||||||
|
new { Name = "工艺", Value = "4nm" },
|
||||||
|
new { Name = "核心数", Value = "8" },
|
||||||
|
new { Name = "主频", Value = "3.05GHz" },
|
||||||
|
new { Name = "GPU", Value = "Mali-G715 MC10" }
|
||||||
|
},
|
||||||
|
PerformanceScores = new[] {
|
||||||
|
new { Benchmark = "Geekbench 5 Single-Core", Score = 1424 },
|
||||||
|
new { Benchmark = "Geekbench 5 Multi-Core", Score = 4485 },
|
||||||
|
new { Benchmark = "AnTuTu 9", Score = 1245876 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
Id = 4,
|
||||||
|
Name = "Snapdragon 8+ Gen 1",
|
||||||
|
Model = "SM8475",
|
||||||
|
Manufacturer = "Qualcomm",
|
||||||
|
ReleaseYear = 2022,
|
||||||
|
PerformanceScore = 3341,
|
||||||
|
CurrentRank = 4,
|
||||||
|
ImageUrl = "/images/placeholder.svg",
|
||||||
|
CategoryId = 1,
|
||||||
|
Description = "高通骁龙8+ Gen 1是2022年推出的旗舰移动处理器,采用4nm工艺制程。",
|
||||||
|
Specifications = new[] {
|
||||||
|
new { Name = "工艺", Value = "4nm" },
|
||||||
|
new { Name = "核心数", Value = "8" },
|
||||||
|
new { Name = "主频", Value = "3.2GHz" },
|
||||||
|
new { Name = "GPU", Value = "Adreno 730" }
|
||||||
|
},
|
||||||
|
PerformanceScores = new[] {
|
||||||
|
new { Benchmark = "Geekbench 5 Single-Core", Score = 1314 },
|
||||||
|
new { Benchmark = "Geekbench 5 Multi-Core", Score = 4185 },
|
||||||
|
new { Benchmark = "AnTuTu 9", Score = 1145876 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var product = allProducts.FirstOrDefault(p => p.Id == id);
|
||||||
|
if (product == null)
|
||||||
|
{
|
||||||
|
return Results.NotFound(new { Message = "产品不存在" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results.Ok(product);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加产品搜索API端点
|
||||||
|
app.MapGet("/api/products/search", (string q, int? categoryId) =>
|
||||||
|
{
|
||||||
|
// 模拟产品数据
|
||||||
|
var allProducts = new[]
|
||||||
|
{
|
||||||
|
new { Id = 1, Name = "Snapdragon 8 Gen 2", Model = "SM8550-AB", Manufacturer = "Qualcomm", ReleaseYear = 2022, PerformanceScore = 3879, CurrentRank = 1, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 2, Name = "A16 Bionic", Model = "A16 Bionic", Manufacturer = "Apple", ReleaseYear = 2022, PerformanceScore = 3756, CurrentRank = 2, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 3, Name = "Dimensity 9200", Model = "MT6985", Manufacturer = "MediaTek", ReleaseYear = 2022, PerformanceScore = 3512, CurrentRank = 3, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 4, Name = "Snapdragon 8+ Gen 1", Model = "SM8475", Manufacturer = "Qualcomm", ReleaseYear = 2022, PerformanceScore = 3341, CurrentRank = 4, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 5, Name = "A15 Bionic", Model = "A15 Bionic", Manufacturer = "Apple", ReleaseYear = 2021, PerformanceScore = 3215, CurrentRank = 5, ImageUrl = "/images/placeholder.svg", CategoryId = 1 },
|
||||||
|
new { Id = 6, Name = "Adreno 740", Model = "Adreno 740", Manufacturer = "Qualcomm", ReleaseYear = 2022, PerformanceScore = 14350, CurrentRank = 1, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 7, Name = "Apple A16 GPU", Model = "A16 GPU", Manufacturer = "Apple", ReleaseYear = 2022, PerformanceScore = 13980, CurrentRank = 2, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 8, Name = "Mali-G715 MC10", Model = "Mali-G715", Manufacturer = "ARM", ReleaseYear = 2022, PerformanceScore = 12150, CurrentRank = 3, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 9, Name = "Adreno 730", Model = "Adreno 730", Manufacturer = "Qualcomm", ReleaseYear = 2022, PerformanceScore = 11020, CurrentRank = 4, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 10, Name = "Apple A15 GPU", Model = "A15 GPU", Manufacturer = "Apple", ReleaseYear = 2021, PerformanceScore = 10560, CurrentRank = 5, ImageUrl = "/images/placeholder.svg", CategoryId = 2 },
|
||||||
|
new { Id = 11, Name = "Intel Core i9-13900K", Model = "i9-13900K", Manufacturer = "Intel", ReleaseYear = 2022, PerformanceScore = 3176, CurrentRank = 1, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 12, Name = "AMD Ryzen 9 7950X", Model = "Ryzen 9 7950X", Manufacturer = "AMD", ReleaseYear = 2022, PerformanceScore = 3095, CurrentRank = 2, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 13, Name = "Intel Core i7-13700K", Model = "i7-13700K", Manufacturer = "Intel", ReleaseYear = 2022, PerformanceScore = 2956, CurrentRank = 3, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 14, Name = "AMD Ryzen 9 5900X", Model = "Ryzen 9 5900X", Manufacturer = "AMD", ReleaseYear = 2020, PerformanceScore = 2835, CurrentRank = 4, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 15, Name = "Intel Core i5-13600K", Model = "i5-13600K", Manufacturer = "Intel", ReleaseYear = 2022, PerformanceScore = 2742, CurrentRank = 5, ImageUrl = "/images/placeholder.svg", CategoryId = 3 },
|
||||||
|
new { Id = 16, Name = "NVIDIA GeForce RTX 4090", Model = "RTX 4090", Manufacturer = "NVIDIA", ReleaseYear = 2022, PerformanceScore = 38928, CurrentRank = 1, ImageUrl = "/images/placeholder.svg", CategoryId = 4 },
|
||||||
|
new { Id = 17, Name = "NVIDIA GeForce RTX 4080", Model = "RTX 4080", Manufacturer = "NVIDIA", ReleaseYear = 2022, PerformanceScore = 32168, CurrentRank = 2, ImageUrl = "/images/placeholder.svg", CategoryId = 4 },
|
||||||
|
new { Id = 18, Name = "NVIDIA GeForce RTX 3090 Ti", Model = "RTX 3090 Ti", Manufacturer = "NVIDIA", ReleaseYear = 2022, PerformanceScore = 28595, CurrentRank = 3, ImageUrl = "/images/placeholder.svg", CategoryId = 4 },
|
||||||
|
new { Id = 19, Name = "AMD Radeon RX 7900 XTX", Model = "RX 7900 XTX", Manufacturer = "AMD", ReleaseYear = 2022, PerformanceScore = 27850, CurrentRank = 4, ImageUrl = "/images/placeholder.svg", CategoryId = 4 },
|
||||||
|
new { Id = 20, Name = "NVIDIA GeForce RTX 3090", Model = "RTX 3090", Manufacturer = "NVIDIA", ReleaseYear = 2020, PerformanceScore = 26420, CurrentRank = 5, ImageUrl = "/images/placeholder.svg", CategoryId = 4 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据类别ID筛选
|
||||||
|
var filteredProducts = categoryId.HasValue
|
||||||
|
? allProducts.Where(p => p.CategoryId == categoryId.Value).ToArray()
|
||||||
|
: allProducts;
|
||||||
|
|
||||||
|
// 根据搜索关键词筛选
|
||||||
|
if (!string.IsNullOrWhiteSpace(q))
|
||||||
|
{
|
||||||
|
filteredProducts = filteredProducts.Where(p =>
|
||||||
|
p.Name.Contains(q, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
p.Model.Contains(q, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
p.Manufacturer.Contains(q, StringComparison.OrdinalIgnoreCase)
|
||||||
|
).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredProducts;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加产品对比API端点
|
||||||
|
app.MapPost("/api/comparison", async (HttpRequest request) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 读取请求体
|
||||||
|
var requestBody = await new StreamReader(request.Body).ReadToEndAsync();
|
||||||
|
|
||||||
|
// 尝试解析为JSON对象
|
||||||
|
dynamic jsonBody = JsonSerializer.Deserialize<Dictionary<string, object>>(requestBody);
|
||||||
|
|
||||||
|
// 提取productIds数组
|
||||||
|
if (jsonBody == null || !jsonBody.ContainsKey("productIds"))
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new { Message = "请求体必须包含productIds字段" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取productIds数组
|
||||||
|
var productIdsJson = jsonBody["productIds"].ToString();
|
||||||
|
var productIds = JsonSerializer.Deserialize<int[]>(productIdsJson);
|
||||||
|
|
||||||
|
// 验证产品ID数量
|
||||||
|
if (productIds == null || productIds.Length < 2 || productIds.Length > 4)
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new { Message = "产品对比需要2-4个产品ID" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟产品详情数据
|
||||||
|
var allProducts = new[]
|
||||||
|
{
|
||||||
|
new {
|
||||||
|
Id = 1,
|
||||||
|
Name = "Snapdragon 8 Gen 2",
|
||||||
|
Model = "SM8550-AB",
|
||||||
|
Manufacturer = "Qualcomm",
|
||||||
|
ReleaseYear = 2022,
|
||||||
|
PerformanceScore = 3879,
|
||||||
|
CurrentRank = 1,
|
||||||
|
ImageUrl = "/images/placeholder.svg",
|
||||||
|
CategoryId = 1,
|
||||||
|
Description = "高通骁龙8 Gen 2是2022年推出的旗舰移动处理器,采用4nm工艺制程。",
|
||||||
|
Specifications = new[] {
|
||||||
|
new { Name = "工艺", Value = "4nm" },
|
||||||
|
new { Name = "核心数", Value = "8" },
|
||||||
|
new { Name = "主频", Value = "3.2GHz" },
|
||||||
|
new { Name = "GPU", Value = "Adreno 740" }
|
||||||
|
},
|
||||||
|
PerformanceScores = new[] {
|
||||||
|
new { Benchmark = "Geekbench 5 Single-Core", Score = 1524 },
|
||||||
|
new { Benchmark = "Geekbench 5 Multi-Core", Score = 5352 },
|
||||||
|
new { Benchmark = "AnTuTu 9", Score = 1314582 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
Id = 2,
|
||||||
|
Name = "A16 Bionic",
|
||||||
|
Model = "A16 Bionic",
|
||||||
|
Manufacturer = "Apple",
|
||||||
|
ReleaseYear = 2022,
|
||||||
|
PerformanceScore = 3756,
|
||||||
|
CurrentRank = 2,
|
||||||
|
ImageUrl = "/images/placeholder.svg",
|
||||||
|
CategoryId = 1,
|
||||||
|
Description = "苹果A16 Bionic是2022年推出的移动处理器,采用4nm工艺制程。",
|
||||||
|
Specifications = new[] {
|
||||||
|
new { Name = "工艺", Value = "4nm" },
|
||||||
|
new { Name = "核心数", Value = "6" },
|
||||||
|
new { Name = "主频", Value = "3.46GHz" },
|
||||||
|
new { Name = "GPU", Value = "Apple A16 GPU" }
|
||||||
|
},
|
||||||
|
PerformanceScores = new[] {
|
||||||
|
new { Benchmark = "Geekbench 5 Single-Core", Score = 1874 },
|
||||||
|
new { Benchmark = "Geekbench 5 Multi-Core", Score = 5372 },
|
||||||
|
new { Benchmark = "AnTuTu 9", Score = 1425876 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
Id = 3,
|
||||||
|
Name = "Dimensity 9200",
|
||||||
|
Model = "MT6985",
|
||||||
|
Manufacturer = "MediaTek",
|
||||||
|
ReleaseYear = 2022,
|
||||||
|
PerformanceScore = 3512,
|
||||||
|
CurrentRank = 3,
|
||||||
|
ImageUrl = "/images/placeholder.svg",
|
||||||
|
CategoryId = 1,
|
||||||
|
Description = "联发科天玑9200是2022年推出的旗舰移动处理器,采用4nm工艺制程。",
|
||||||
|
Specifications = new[] {
|
||||||
|
new { Name = "工艺", Value = "4nm" },
|
||||||
|
new { Name = "核心数", Value = "8" },
|
||||||
|
new { Name = "主频", Value = "3.05GHz" },
|
||||||
|
new { Name = "GPU", Value = "Mali-G715 MC10" }
|
||||||
|
},
|
||||||
|
PerformanceScores = new[] {
|
||||||
|
new { Benchmark = "Geekbench 5 Single-Core", Score = 1424 },
|
||||||
|
new { Benchmark = "Geekbench 5 Multi-Core", Score = 4485 },
|
||||||
|
new { Benchmark = "AnTuTu 9", Score = 1245876 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
Id = 4,
|
||||||
|
Name = "Snapdragon 8+ Gen 1",
|
||||||
|
Model = "SM8475",
|
||||||
|
Manufacturer = "Qualcomm",
|
||||||
|
ReleaseYear = 2022,
|
||||||
|
PerformanceScore = 3341,
|
||||||
|
CurrentRank = 4,
|
||||||
|
ImageUrl = "/images/placeholder.svg",
|
||||||
|
CategoryId = 1,
|
||||||
|
Description = "高通骁龙8+ Gen 1是2022年推出的旗舰移动处理器,采用4nm工艺制程。",
|
||||||
|
Specifications = new[] {
|
||||||
|
new { Name = "工艺", Value = "4nm" },
|
||||||
|
new { Name = "核心数", Value = "8" },
|
||||||
|
new { Name = "主频", Value = "3.2GHz" },
|
||||||
|
new { Name = "GPU", Value = "Adreno 730" }
|
||||||
|
},
|
||||||
|
PerformanceScores = new[] {
|
||||||
|
new { Benchmark = "Geekbench 5 Single-Core", Score = 1314 },
|
||||||
|
new { Benchmark = "Geekbench 5 Multi-Core", Score = 4185 },
|
||||||
|
new { Benchmark = "AnTuTu 9", Score = 1145876 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取请求的产品
|
||||||
|
var selectedProducts = allProducts.Where(p => productIds.Contains(p.Id)).ToArray();
|
||||||
|
|
||||||
|
// 检查是否找到了所有请求的产品
|
||||||
|
if (selectedProducts.Length != productIds.Length)
|
||||||
|
{
|
||||||
|
return Results.NotFound(new { Message = "一个或多个产品不存在" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建对比数据
|
||||||
|
var comparisonData = new {
|
||||||
|
Products = selectedProducts,
|
||||||
|
ComparisonMatrix = new {
|
||||||
|
PerformanceScore = selectedProducts.Select(p => new {
|
||||||
|
ProductId = p.Id,
|
||||||
|
ProductName = p.Name,
|
||||||
|
Value = p.PerformanceScore,
|
||||||
|
IsBest = p.PerformanceScore == selectedProducts.Max(x => x.PerformanceScore),
|
||||||
|
IsWorst = p.PerformanceScore == selectedProducts.Min(x => x.PerformanceScore)
|
||||||
|
}).ToArray(),
|
||||||
|
ReleaseYear = selectedProducts.Select(p => new {
|
||||||
|
ProductId = p.Id,
|
||||||
|
ProductName = p.Name,
|
||||||
|
Value = p.ReleaseYear,
|
||||||
|
IsBest = p.ReleaseYear == selectedProducts.Max(x => x.ReleaseYear),
|
||||||
|
IsWorst = p.ReleaseYear == selectedProducts.Min(x => x.ReleaseYear)
|
||||||
|
}).ToArray()
|
||||||
|
},
|
||||||
|
PerformanceComparison = new {
|
||||||
|
Benchmarks = new[] {
|
||||||
|
new {
|
||||||
|
Name = "Geekbench 5 Single-Core",
|
||||||
|
Values = selectedProducts.Select(p => new {
|
||||||
|
ProductId = p.Id,
|
||||||
|
ProductName = p.Name,
|
||||||
|
Value = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Single-Core")?.Score ?? 0,
|
||||||
|
IsBest = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Single-Core")?.Score == selectedProducts.Max(x => x.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Single-Core")?.Score ?? 0),
|
||||||
|
IsWorst = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Single-Core")?.Score == selectedProducts.Min(x => x.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Single-Core")?.Score ?? int.MaxValue)
|
||||||
|
}).ToArray()
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
Name = "Geekbench 5 Multi-Core",
|
||||||
|
Values = selectedProducts.Select(p => new {
|
||||||
|
ProductId = p.Id,
|
||||||
|
ProductName = p.Name,
|
||||||
|
Value = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Multi-Core")?.Score ?? 0,
|
||||||
|
IsBest = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Multi-Core")?.Score == selectedProducts.Max(x => x.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Multi-Core")?.Score ?? 0),
|
||||||
|
IsWorst = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Multi-Core")?.Score == selectedProducts.Min(x => x.PerformanceScores.FirstOrDefault(s => s.Benchmark == "Geekbench 5 Multi-Core")?.Score ?? int.MaxValue)
|
||||||
|
}).ToArray()
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
Name = "AnTuTu 9",
|
||||||
|
Values = selectedProducts.Select(p => new {
|
||||||
|
ProductId = p.Id,
|
||||||
|
ProductName = p.Name,
|
||||||
|
Value = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "AnTuTu 9")?.Score ?? 0,
|
||||||
|
IsBest = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "AnTuTu 9")?.Score == selectedProducts.Max(x => x.PerformanceScores.FirstOrDefault(s => s.Benchmark == "AnTuTu 9")?.Score ?? 0),
|
||||||
|
IsWorst = p.PerformanceScores.FirstOrDefault(s => s.Benchmark == "AnTuTu 9")?.Score == selectedProducts.Min(x => x.PerformanceScores.FirstOrDefault(s => s.Benchmark == "AnTuTu 9")?.Score ?? int.MaxValue)
|
||||||
|
}).ToArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Results.Ok(comparisonData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new { Message = $"处理请求时出错: {ex.Message}" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/", () => "Hello World!");
|
||||||
|
|
||||||
|
app.Run();
|
||||||
23
TestAPI/Properties/launchSettings.json
Normal file
23
TestAPI/Properties/launchSettings.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "http://localhost:5034",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "https://localhost:7100;http://localhost:5034",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
TestAPI/TestAPI.csproj
Normal file
9
TestAPI/TestAPI.csproj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
8
TestAPI/appsettings.Development.json
Normal file
8
TestAPI/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
TestAPI/appsettings.json
Normal file
9
TestAPI/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
23
TestAPI/bin/Debug/net9.0/TestAPI.deps.json
Normal file
23
TestAPI/bin/Debug/net9.0/TestAPI.deps.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v9.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v9.0": {
|
||||||
|
"TestAPI/1.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"TestAPI.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"TestAPI/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
TestAPI/bin/Debug/net9.0/TestAPI.dll
Normal file
BIN
TestAPI/bin/Debug/net9.0/TestAPI.dll
Normal file
Binary file not shown.
BIN
TestAPI/bin/Debug/net9.0/TestAPI.exe
Normal file
BIN
TestAPI/bin/Debug/net9.0/TestAPI.exe
Normal file
Binary file not shown.
BIN
TestAPI/bin/Debug/net9.0/TestAPI.pdb
Normal file
BIN
TestAPI/bin/Debug/net9.0/TestAPI.pdb
Normal file
Binary file not shown.
19
TestAPI/bin/Debug/net9.0/TestAPI.runtimeconfig.json
Normal file
19
TestAPI/bin/Debug/net9.0/TestAPI.runtimeconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"runtimeOptions": {
|
||||||
|
"tfm": "net9.0",
|
||||||
|
"frameworks": [
|
||||||
|
{
|
||||||
|
"name": "Microsoft.NETCore.App",
|
||||||
|
"version": "9.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft.AspNetCore.App",
|
||||||
|
"version": "9.0.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configProperties": {
|
||||||
|
"System.GC.Server": true,
|
||||||
|
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"Version":1,"ManifestType":"Build","Endpoints":[]}
|
||||||
8
TestAPI/bin/Debug/net9.0/appsettings.Development.json
Normal file
8
TestAPI/bin/Debug/net9.0/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
TestAPI/bin/Debug/net9.0/appsettings.json
Normal file
9
TestAPI/bin/Debug/net9.0/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// <autogenerated />
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0")]
|
||||||
22
TestAPI/obj/Debug/net9.0/TestAPI.AssemblyInfo.cs
Normal file
22
TestAPI/obj/Debug/net9.0/TestAPI.AssemblyInfo.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
[assembly: System.Reflection.AssemblyCompanyAttribute("TestAPI")]
|
||||||
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyProductAttribute("TestAPI")]
|
||||||
|
[assembly: System.Reflection.AssemblyTitleAttribute("TestAPI")]
|
||||||
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|
||||||
|
// 由 MSBuild WriteCodeFragment 类生成。
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ccdd8558c5bd69980236f6ef7435019aea79860a1fdbecb265564d3b99885b5a
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
is_global = true
|
||||||
|
build_property.TargetFramework = net9.0
|
||||||
|
build_property.TargetPlatformMinVersion =
|
||||||
|
build_property.UsingMicrosoftNETSdkWeb = true
|
||||||
|
build_property.ProjectTypeGuids =
|
||||||
|
build_property.InvariantGlobalization =
|
||||||
|
build_property.PlatformNeutralAssembly =
|
||||||
|
build_property.EnforceExtendedAnalyzerRules =
|
||||||
|
build_property._SupportedPlatformList = Linux,macOS,Windows
|
||||||
|
build_property.RootNamespace = TestAPI
|
||||||
|
build_property.RootNamespace = TestAPI
|
||||||
|
build_property.ProjectDir = C:\work\电脑硬件-01\TestAPI\
|
||||||
|
build_property.EnableComHosting =
|
||||||
|
build_property.EnableGeneratedComInterfaceComImportInterop =
|
||||||
|
build_property.RazorLangVersion = 9.0
|
||||||
|
build_property.SupportLocalizedComponentNames =
|
||||||
|
build_property.GenerateRazorMetadataSourceChecksumAttributes =
|
||||||
|
build_property.MSBuildProjectDirectory = C:\work\电脑硬件-01\TestAPI
|
||||||
|
build_property._RazorSourceGeneratorDebug =
|
||||||
|
build_property.EffectiveAnalysisLevelStyle = 9.0
|
||||||
|
build_property.EnableCodeStyleSeverity =
|
||||||
17
TestAPI/obj/Debug/net9.0/TestAPI.GlobalUsings.g.cs
Normal file
17
TestAPI/obj/Debug/net9.0/TestAPI.GlobalUsings.g.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// <auto-generated/>
|
||||||
|
global using global::Microsoft.AspNetCore.Builder;
|
||||||
|
global using global::Microsoft.AspNetCore.Hosting;
|
||||||
|
global using global::Microsoft.AspNetCore.Http;
|
||||||
|
global using global::Microsoft.AspNetCore.Routing;
|
||||||
|
global using global::Microsoft.Extensions.Configuration;
|
||||||
|
global using global::Microsoft.Extensions.DependencyInjection;
|
||||||
|
global using global::Microsoft.Extensions.Hosting;
|
||||||
|
global using global::Microsoft.Extensions.Logging;
|
||||||
|
global using global::System;
|
||||||
|
global using global::System.Collections.Generic;
|
||||||
|
global using global::System.IO;
|
||||||
|
global using global::System.Linq;
|
||||||
|
global using global::System.Net.Http;
|
||||||
|
global using global::System.Net.Http.Json;
|
||||||
|
global using global::System.Threading;
|
||||||
|
global using global::System.Threading.Tasks;
|
||||||
BIN
TestAPI/obj/Debug/net9.0/TestAPI.assets.cache
Normal file
BIN
TestAPI/obj/Debug/net9.0/TestAPI.assets.cache
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
629dc1ba4c6ea1c70ecea85384c28652dcd9f627da004e854aea08234c082e60
|
||||||
27
TestAPI/obj/Debug/net9.0/TestAPI.csproj.FileListAbsolute.txt
Normal file
27
TestAPI/obj/Debug/net9.0/TestAPI.csproj.FileListAbsolute.txt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\rpswa.dswa.cache.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\TestAPI.GeneratedMSBuildEditorConfig.editorconfig
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\TestAPI.AssemblyInfoInputs.cache
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\TestAPI.AssemblyInfo.cs
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\TestAPI.csproj.CoreCompileInputs.cache
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\TestAPI.MvcApplicationPartsAssemblyInfo.cache
|
||||||
|
C:\work\电脑硬件-01\TestAPI\bin\Debug\net9.0\appsettings.Development.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\bin\Debug\net9.0\appsettings.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\bin\Debug\net9.0\TestAPI.staticwebassets.endpoints.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\bin\Debug\net9.0\TestAPI.exe
|
||||||
|
C:\work\电脑硬件-01\TestAPI\bin\Debug\net9.0\TestAPI.deps.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\bin\Debug\net9.0\TestAPI.runtimeconfig.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\bin\Debug\net9.0\TestAPI.dll
|
||||||
|
C:\work\电脑硬件-01\TestAPI\bin\Debug\net9.0\TestAPI.pdb
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\rjimswa.dswa.cache.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\rjsmrazor.dswa.cache.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\rjsmcshtml.dswa.cache.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\scopedcss\bundle\TestAPI.styles.css
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\staticwebassets.build.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\staticwebassets.build.json.cache
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\staticwebassets.development.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\staticwebassets.build.endpoints.json
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\TestAPI.dll
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\refint\TestAPI.dll
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\TestAPI.pdb
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\TestAPI.genruntimeconfig.cache
|
||||||
|
C:\work\电脑硬件-01\TestAPI\obj\Debug\net9.0\ref\TestAPI.dll
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user