Cursor rule
.cursor/rules/startup-framework.mdcCodeSpirit 统一启动框架规范 - API项目配置标准化
Cursor rules
Quality
54/100
Scores the file, not the repository.Length
1,048 words
28 headings · 19 code blocksRepository
56
— · pushed 134 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# 统一启动框架规范89## 快速开始1011### Program.cs(标准模板)12```csharp13using CodeSpirit.ExamApi.Configuration;14using CodeSpirit.Shared.Startup;15using System.Text;1617Console.OutputEncoding = Encoding.UTF8;1819var builder = WebApplication.CreateBuilder(args);2021// 1. 注册服务22builder.AddCodeSpiritApi<ExamApiConfiguration>();2324var app = builder.Build();2526try27{28 // 2. 配置中间件和初始化数据库29 await app.UseCodeSpiritApiAsync<ExamApiConfiguration>();30 app.Run();31}32catch (Exception ex)33{34 var logger = app.Services.GetRequiredService<ILogger<Program>>();35 logger.LogError(ex, "服务启动过程中发生错误");36}37```3839> ⚠️ **规范**:不要在 `Program.cs` 中添加额外配置,所有配置放在 API 配置类中。4041---4243## API 配置类4445### 位置和命名46- **位置**:`{ProjectName}/Configuration/` 文件夹47- **命名**:`{ApiName}Configuration`(如 `ExamApiConfiguration`)48- **继承**:`BaseApiConfiguration`4950### 最小配置类51```csharp52namespace CodeSpirit.ExamApi.Configuration;5354public class ExamApiConfiguration : BaseApiConfiguration55{56 /// <summary>服务名称,用于 Aspire 服务发现</summary>57 public override string ServiceName => "exam";5859 /// <summary>数据库连接字符串键名</summary>60 public override string ConnectionStringKey => "exam-api";61}62```6364---6566## 核心方法6768### ConfigureServices - 服务注册6970#### 简化配置方式(推荐)7172使用扩展方法简化配置,减少重复代码:7374```csharp75public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)76{77 // ⚠️ 必须调用基类方法(初始化路径前缀配置)78 base.ConfigureServices(services, configuration);7980 // 配置标准数据库服务(多数据库支持、仓储模式)81 this.ConfigureStandardDatabaseServices<ExamDbContext, MySqlExamDbContext, SqlServerExamDbContext>(82 services, configuration);8384 // 配置标准基础设施服务(事件总线、HTTP客户端)+ 可选组件(多租户、设置管理)85 this.ConfigureStandardInfrastructureServices(services, configuration, (s, c) =>86 {87 s.AddCodeSpiritMultiTenant(c);88 s.AddSettingsManagerWithDatabase(c);89 });9091 // 只配置特定业务服务92 services.AddLLMServices();93 AddExamSpecificServices(services);94}95```9697#### 传统配置方式9899如果需要更多控制,可以使用传统方式:100101```csharp102public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)103{104 // ⚠️ 必须调用基类方法(初始化路径前缀配置)105 base.ConfigureServices(services, configuration);106107 // 配置多数据库支持(推荐方式)108 DatabaseMigrationHelper.ConfigureMultiDatabaseDbContext<109 ExamDbContext, MySqlExamDbContext, SqlServerExamDbContext>(110 services, configuration, ConnectionStringKey);111112 // 注册仓储模式113 services.AddScoped(typeof(IRepository<>), typeof(Repository<>));114115 // 添加多租户支持116 services.AddCodeSpiritMultiTenant(configuration);117118 // 其他服务注册...119}120```121122#### 常用服务注册方法123| 方法 | 说明 |124|------|------|125| `services.AddCodeSpiritMultiTenant(configuration)` | 多租户支持 |126| `services.AddEventBus()` | 事件总线 |127| `services.AddCodeSpiritCaching(configuration)` | 统一缓存服务 |128| `services.AddLLMServices()` | LLM 服务 |129| `services.AddAiFormFillEndpoints()` | AI 表单填充端点 |130| `services.AddSettingsManagerWithDatabase(configuration)` | 设置管理 |131| `services.AddScheduledTasks()` | 定时任务 |132| `services.AddChartServices()` | 图表服务 |133134#### 线程池配置(可选)135```csharp136// 高并发服务137ThreadPoolConfiguration.ConfigureThreadPool(138 ThreadPoolConfiguration.ServiceTier.High,139 expectedInstances: 3,140 logger);141142// 服务等级:Low, Medium, High143```144145---146147### 中间件配置148149#### 1. ConfigurePreAuthenticationMiddlewareAsync - 认证前150在认证之前执行,用于租户解析等:151```csharp152public override Task ConfigurePreAuthenticationMiddlewareAsync(WebApplication app)153{154 app.UseCodeSpiritMultiTenant();155 return Task.CompletedTask;156}157```158159#### 2. ConfigurePreControllerMiddlewareAsync - 控制器前160在控制器映射之前执行:161```csharp162public override Task ConfigurePreControllerMiddlewareAsync(WebApplication app)163{164 // 通常审计由网关处理,API 服务不需要165 return Task.CompletedTask;166}167```168169#### 3. ConfigureMiddlewareAsync - 自定义中间件170在通用中间件之后执行:171172**简化配置方式(推荐):**173174```csharp175public override async Task ConfigureMiddlewareAsync(WebApplication app)176{177 // 配置标准中间件(聚合器)+ 可选组件(多租户、AI表单填充)178 await this.ConfigureStandardMiddlewareAsync(app, a =>179 {180 a.UseCodeSpiritMultiTenant();181 a.UseAiFormFillEndpoints();182 });183184 // 只配置特定中间件185 app.MapHub<ExamHub>("/exam-hub");186}187```188189**传统配置方式:**190191```csharp192public override async Task ConfigureMiddlewareAsync(WebApplication app)193{194 // 多租户中间件195 app.UseCodeSpiritMultiTenant();196197 // 聚合器中间件198 app.UseCodeSpiritAggregator();199200 // AI 表单填充端点201 app.UseAiFormFillEndpoints();202203 // SignalR Hub 映射204 app.MapHub<ExamHub>("/exam-hub");205206 await Task.CompletedTask;207}208```209210---211212### InitializeDatabaseAsync - 数据库初始化213214**简化配置方式(推荐):**215216```csharp217public override async Task InitializeDatabaseAsync(WebApplication app)218{219 // 使用标准数据库初始化方法220 // 自动应用迁移和初始化种子数据(如果 DbContext 实现了 IInitializableDbContext)221 await this.InitializeStandardDatabaseAsync<ExamDbContext, MySqlExamDbContext, SqlServerExamDbContext>(222 app, "ExamApi");223}224```225226**传统配置方式:**227228```csharp229public override async Task InitializeDatabaseAsync(WebApplication app)230{231 using var scope = app.Services.CreateScope();232 var services = scope.ServiceProvider;233 var logger = services.GetRequiredService<ILogger<ExamApiConfiguration>>();234 var configuration = services.GetRequiredService<IConfiguration>();235236 try237 {238 // 1. 自动应用数据库迁移239 await DatabaseMigrationHelper.ApplyDatabaseMigrationsAsync<240 MySqlExamDbContext,241 SqlServerExamDbContext>(242 services, configuration, logger, "ExamApi");243244 // 2. 初始化种子数据245 var context = services.GetRequiredService<ExamDbContext>();246 await context.InitializeDatabaseAsync();247248 logger.LogInformation("数据库初始化完成");249 }250 catch (Exception ex)251 {252 logger.LogError(ex, "初始化数据库时发生错误:{Message}", ex.Message);253 throw;254 }255}256```257258**注意:** 如果 DbContext 实现了 `IInitializableDbContext` 接口,标准初始化方法会自动调用 `InitializeDatabaseAsync()` 方法。259260---261262## 中间件执行顺序263264```265请求 ──▶ CORS266 ↓267 ApplicationId 中间件268 ↓269 ┌──────────────────────────────────────┐270 │ ConfigurePreAuthenticationMiddlewareAsync │ ← 插入点1(认证前)271 │ 示例:多租户解析 │272 └──────────────────────────────────────┘273 ↓274 Authentication & Authorization275 ↓276 ┌──────────────────────────────────────┐277 │ ConfigurePreControllerMiddlewareAsync │ ← 插入点2(控制器前)278 │ 示例:审计日志 │279 └──────────────────────────────────────┘280 ↓281 Controller Mapping282 ↓283 AMIS UI / Authorization / Navigation284 ↓285 ┌──────────────────────────────────────┐286 │ ConfigureMiddlewareAsync │ ← 插入点3(自定义)287 │ 示例:聚合器、SignalR Hub │288 └──────────────────────────────────────┘289 ↓290 响应291```292293---294295## 统一框架自动配置296297无需手动配置,框架自动完成:298- ✅ Aspire 服务默认配置(OpenTelemetry、健康检查等)299- ✅ Scrutor 自动依赖注入(`IScopedDependency` 等)300- ✅ JWT 认证配置301- ✅ Redis 分布式缓存302- ✅ AutoMapper 自动扫描303- ✅ CORS 配置304- ✅ 控制器配置(路径前缀路由约定)305- ✅ 仓储模式注册306- ✅ 异常处理中间件307- ✅ 数据库迁移应用308309---310311## 路径前缀配置312313### PathPrefixOptions 属性314```csharp315// 基类已定义,从配置文件自动读取316public virtual PathPrefixOptions PathPrefixOptions { get; protected set; }317```318319配置文件 `appsettings.json`:320```json321{322 "PathPrefix": {323 "Enabled": true,324 "Prefix": "/exam"325 }326}327```328329---330331## 完整配置类示例332333### 简化配置示例(推荐)334335```csharp336using CodeSpirit.ExamApi.Data;337using CodeSpirit.Shared.Performance;338using CodeSpirit.Shared.Startup;339340namespace CodeSpirit.ExamApi.Configuration;341342public class ExamApiConfiguration : BaseApiConfiguration343{344 public override string ServiceName => "exam";345 public override string ConnectionStringKey => "exam-api";346347 public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)348 {349 // 线程池配置(可选)350 var logger = services.BuildServiceProvider()351 .GetService<ILoggerFactory>()?.CreateLogger<ExamApiConfiguration>();352 ThreadPoolConfiguration.ConfigureThreadPool(353 ThreadPoolConfiguration.ServiceTier.High,354 expectedInstances: 3,355 logger);356357 // 调用基类(初始化路径前缀)358 base.ConfigureServices(services, configuration);359360 // 配置标准数据库服务(多数据库支持、仓储模式)361 this.ConfigureStandardDatabaseServices<ExamDbContext, MySqlExamDbContext, SqlServerExamDbContext>(362 services, configuration);363364 // 配置标准基础设施服务(事件总线、HTTP客户端)+ 可选组件(多租户、设置管理)365 this.ConfigureStandardInfrastructureServices(services, configuration, (s, c) =>366 {367 s.AddCodeSpiritMultiTenant(c);368 s.AddSettingsManagerWithDatabase(c);369 });370371 // 只配置特定业务服务372 services.AddLLMServices();373 }374375 public override async Task ConfigureMiddlewareAsync(WebApplication app)376 {377 // 配置标准中间件(聚合器)+ 可选组件(多租户、AI表单填充)378 await this.ConfigureStandardMiddlewareAsync(app, a =>379 {380 a.UseCodeSpiritMultiTenant();381 a.UseAiFormFillEndpoints();382 });383 }384385 public override async Task InitializeDatabaseAsync(WebApplication app)386 {387 // 使用标准数据库初始化方法388 await this.InitializeStandardDatabaseAsync<ExamDbContext, MySqlExamDbContext, SqlServerExamDbContext>(389 app, "ExamApi");390 }391}392```393394### 传统配置示例395396```csharp397using CodeSpirit.Aggregator;398using CodeSpirit.AiFormFill;399using CodeSpirit.ExamApi.Data;400using CodeSpirit.MultiTenant.Extensions;401using CodeSpirit.Shared.Data;402using CodeSpirit.Shared.Performance;403using CodeSpirit.Shared.Repositories;404using CodeSpirit.Shared.Startup;405406namespace CodeSpirit.ExamApi.Configuration;407408public class ExamApiConfiguration : BaseApiConfiguration409{410 public override string ServiceName => "exam";411 public override string ConnectionStringKey => "exam-api";412413 public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)414 {415 // 线程池配置416 var logger = services.BuildServiceProvider()417 .GetService<ILoggerFactory>()?.CreateLogger<ExamApiConfiguration>();418 ThreadPoolConfiguration.ConfigureThreadPool(419 ThreadPoolConfiguration.ServiceTier.High,420 expectedInstances: 3,421 logger);422423 // 调用基类(初始化路径前缀)424 base.ConfigureServices(services, configuration);425426 // 数据库配置427 DatabaseMigrationHelper.ConfigureMultiDatabaseDbContext<428 ExamDbContext, MySqlExamDbContext, SqlServerExamDbContext>(429 services, configuration, ConnectionStringKey);430431 // 仓储模式432 services.AddScoped(typeof(IRepository<>), typeof(Repository<>));433434 // 多租户435 services.AddCodeSpiritMultiTenant(configuration);436437 // 事件总线438 services.AddEventBus();439 }440441 public override async Task ConfigureMiddlewareAsync(WebApplication app)442 {443 app.UseCodeSpiritMultiTenant();444 app.UseCodeSpiritAggregator();445 app.UseAiFormFillEndpoints();446 await Task.CompletedTask;447 }448449 public override async Task InitializeDatabaseAsync(WebApplication app)450 {451 using var scope = app.Services.CreateScope();452 var services = scope.ServiceProvider;453 var logger = services.GetRequiredService<ILogger<ExamApiConfiguration>>();454 var configuration = services.GetRequiredService<IConfiguration>();455456 try457 {458 await DatabaseMigrationHelper.ApplyDatabaseMigrationsAsync<459 MySqlExamDbContext, SqlServerExamDbContext>(460 services, configuration, logger, "ExamApi");461462 var context = services.GetRequiredService<ExamDbContext>();463 await context.InitializeDatabaseAsync();464 }465 catch (Exception ex)466 {467 logger.LogError(ex, "初始化数据库失败:{Message}", ex.Message);468 throw;469 }470 }471}472```473474---475476## 注意事项477478| 规则 | 说明 |479|------|------|480| ✅ 调用 `base.ConfigureServices()` | 必须调用以初始化路径前缀配置 |481| ✅ 使用扩展方法简化配置 | 推荐使用 `ConfigureStandardDatabaseServices`、`ConfigureStandardInfrastructureServices` 等扩展方法 |482| ✅ 使用回调委托配置可选组件 | 通过委托参数显式配置可选组件,避免反射调用 |483| ✅ 使用 `DatabaseMigrationHelper` | 简化多数据库配置 |484| ✅ 实现 `IInitializableDbContext` | 如果 DbContext 需要初始化种子数据,实现此接口 |485| ✅ 异步方法返回 `Task` | 所有中间件配置方法都是异步的 |486| ❌ 在 Program.cs 添加配置 | 所有配置放在 API 配置类中 |487| ❌ 重复注册框架已有服务 | 检查自动配置列表避免重复 |488| ❌ 使用反射调用扩展方法 | 反射调用失去编译时类型安全,且性能较差 |489490---491492## 可选组件配置最佳实践493494### ❌ 错误方式:使用反射调用495496```csharp497// ❌ 不推荐:使用反射动态调用扩展方法498private static void TryInvokeExtensionMethod(IServiceCollection services,499 string namespaceName, string className, string methodName, IConfiguration configuration)500{501 var assembly = AppDomain.CurrentDomain.GetAssemblies()502 .FirstOrDefault(a => a.GetTypes().Any(t => t.Namespace == namespaceName));503 var type = assembly.GetType($"{namespaceName}.{className}");504 var method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);505 method?.Invoke(null, new object[] { services, configuration });506}507```508509**问题**:510- ❌ 编译时无法检测方法签名变更511- ❌ 运行时性能损耗512- ❌ IDE 无法追踪引用关系513- ❌ 错误被默默吞掉,不易察觉514- ❌ 重构时容易遗漏515516### ✅ 正确方式:使用回调委托517518```csharp519// ✅ 推荐:通过回调委托配置可选组件520public static void ConfigureStandardInfrastructureServices(521 this BaseApiConfiguration config,522 IServiceCollection services,523 IConfiguration configuration,524 Action<IServiceCollection, IConfiguration>? additionalConfiguration = null)525{526 // 核心服务(必需)527 services.AddEventBus();528 services.AddHttpClient();529530 // 可选组件通过委托配置531 additionalConfiguration?.Invoke(services, configuration);532}533```534535**调用示例**:536537```csharp538// 显式配置需要的可选组件539this.ConfigureStandardInfrastructureServices(services, configuration, (s, c) =>540{541 s.AddCodeSpiritMultiTenant(c); // 多租户支持542 s.AddSettingsManagerWithDatabase(c); // 设置管理543});544```
Also in xin-lai/CodeSpirit
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| xin-lai/CodeSpirit.cursor/rules/js.mdc · 56 | Cursor rules | apidocs | 46/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/ai-development.mdc · 56 | Cursor rules | api | 46/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/all.mdc · 56 | Cursor rules | testing-strategyapi | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/amis-cards.mdc · 56 | Cursor rules | no sections | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/api-design.mdc · 56 | Cursor rules | no sections | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/controller.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/cs.mdc · 56 | Cursor rules | no sections | 25/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/csproj.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/css.mdc · 56 | Cursor rules | ui | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/database.mdc · 56 | Cursor rules | no sections | 74/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/dependency-injection.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/dto.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/enum.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/i18n.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/naming-conventions.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/package-management.mdc · 56 | Cursor rules | no sections | 74/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/performance.mdc · 56 | Cursor rules | no sections | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/project-structure.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/security.mdc · 56 | Cursor rules | database | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/service.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago |
Diff against .cursor/rules/js.mdc Diff against .cursor/rules/ai-development.mdc Diff against .cursor/rules/all.mdc Diff against .cursor/rules/amis-cards.mdc Diff against .cursor/rules/api-design.mdc Diff against .cursor/rules/controller.mdc Diff against .cursor/rules/cs.mdc Diff against .cursor/rules/csproj.mdc Diff against .cursor/rules/css.mdc Diff against .cursor/rules/database.mdc Diff against .cursor/rules/dependency-injection.mdc Diff against .cursor/rules/dto.mdc Diff against .cursor/rules/enum.mdc Diff against .cursor/rules/i18n.mdc Diff against .cursor/rules/naming-conventions.mdc Diff against .cursor/rules/package-management.mdc Diff against .cursor/rules/performance.mdc Diff against .cursor/rules/project-structure.mdc Diff against .cursor/rules/security.mdc Diff against .cursor/rules/service.mdc
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 3 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago |
