RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/Cursor rules/xin-lai/CodeSpirit

Cursor rule

.cursor/rules/dependency-injection.mdc

CodeSpirit 依赖注入规范 - Scrutor自动注册、生命周期管理

Cursor rules

Quality

54/100

Scores the file, not the repository.

Length

821 words

28 headings · 19 code blocks

Repository

56

— · pushed 134 days ago

Last changed

3 days ago

First indexed 3 days ago.
xin-lai/CodeSpirit/.cursor/rules/dependency-injection.mdcRawGitHub
1---
2description: CodeSpirit 依赖注入规范 - Scrutor自动注册、生命周期管理
3globs:
4 - "*Service.cs"
5 - "**/Services/**/*.cs"
6 - "**/*Seeder*.cs"
7 - "**/*Helper*.cs"
8 - "**/*Handler*.cs"
9 - "**/*Repository*.cs"
10alwaysApply: false
11---
12 
13# 依赖注入规范(Scrutor 自动注册)
14 
15## 概述
16 
17项目使用 Scrutor 库实现基于标记接口的自动依赖注入,无需手动注册服务。
18 
19## 标记接口
20 
21位于 `CodeSpirit.Core.DependencyInjection` 命名空间:
22 
23| 接口 | 生命周期 | 适用场景 |
24|-----|---------|---------|
25| `IScopedDependency` | Scoped | 业务服务、数据库操作、请求相关 |
26| `ITransientDependency` | Transient | 无状态工具类、轻量操作 |
27| `ISingletonDependency` | Singleton | 配置服务、缓存、ID生成器 |
28 
29### 生命周期说明
30 
31```csharp
32// IScopedDependency - 作用域注入
33// 同一个请求中是同一个实例,不同请求是不同实例
34// 推荐:大多数业务服务、DbContext 相关操作
35 
36// ITransientDependency - 瞬时注入
37// 每次注入都创建新实例
38// 推荐:无状态工具类、不持有资源的服务
39 
40// ISingletonDependency - 单例注入
41// 整个应用生命周期只有一个实例
42// 推荐:配置服务、缓存管理、ID生成器
43```
44 
45## 标记方式
46 
47### 方式一:接口继承标记接口(推荐)
48 
49接口继承标记接口,实现类无需再次标记:
50 
51```csharp
52// 接口定义 - 继承 IScopedDependency
53public interface IAuthService : IScopedDependency
54{
55 Task<AuthResultDto> LoginAsync(LoginDto input);
56 Task<bool> LogoutAsync(long userId);
57}
58 
59// 实现类 - 无需标记接口
60public class AuthService : IAuthService
61{
62 private readonly IRepository<User> _userRepository;
63
64 public AuthService(IRepository<User> userRepository)
65 {
66 _userRepository = userRepository;
67 }
68
69 public async Task<AuthResultDto> LoginAsync(LoginDto input)
70 {
71 // 实现逻辑
72 }
73}
74```
75 
76### 方式二:实现类标记接口
77 
78适用于无业务接口的服务类:
79 
80```csharp
81// 无接口的服务类,直接实现标记接口
82public class SeederService : IScopedDependency
83{
84 private readonly IServiceProvider _serviceProvider;
85 private readonly ILogger<SeederService> _logger;
86 
87 public SeederService(IServiceProvider serviceProvider, ILogger<SeederService> logger)
88 {
89 _serviceProvider = serviceProvider;
90 _logger = logger;
91 }
92 
93 public async Task SeedAsync()
94 {
95 // 初始化种子数据
96 }
97}
98```
99 
100### 方式三:同时实现业务接口和标记接口
101 
102适用于需要明确指定生命周期的服务:
103 
104```csharp
105public interface IUserService : IBaseCRUDService<User, long, CreateUserDto, UpdateUserDto, UserQueryDto>
106{
107 Task<UserDto> GetByUsernameAsync(string username);
108}
109 
110public class UserService : BaseCRUDService<User, long, CreateUserDto, UpdateUserDto, UserQueryDto>,
111 IUserService, IScopedDependency
112{
113 public async Task<UserDto> GetByUsernameAsync(string username)
114 {
115 // 实现逻辑
116 }
117}
118```
119 
120## 生命周期选择指南
121 
122### IScopedDependency(作用域 - 最常用)
123 
124```csharp
125// ✅ 业务服务
126public interface IQuestionService : IScopedDependency
127{
128 Task<QuestionDto> GetByIdAsync(long id);
129 Task CreateAsync(CreateQuestionDto dto);
130}
131 
132// ✅ 数据访问服务
133public interface IExamRepository : IScopedDependency
134{
135 Task<Exam> GetWithQuestionsAsync(long examId);
136}
137 
138// ✅ 种子数据服务
139public class TenantSeeder : IScopedDependency
140{
141 public async Task SeedAsync() { }
142}
143```
144 
145### ISingletonDependency(单例)
146 
147```csharp
148// ✅ ID 生成器
149public interface IIdGenerator : ISingletonDependency
150{
151 long NewId();
152}
153 
154// ✅ 缓存服务
155public interface IConfigCacheService : ISingletonDependency
156{
157 Task<string> GetAsync(string key);
158 Task SetAsync(string key, string value, TimeSpan? expiry = null);
159}
160 
161// ✅ 端点扫描器(应用启动时扫描一次)
162public class AiFormFillEndpointScanner : ISingletonDependency
163{
164 public void ScanAssemblies(params Assembly[] assemblies) { }
165}
166 
167// ✅ 本地化设置初始化器
168public class LocalizationSettingsInitializer : ISingletonDependency
169{
170 public void Initialize() { }
171}
172```
173 
174### ITransientDependency(瞬时)
175 
176```csharp
177// ✅ 无状态工具类
178public interface IPasswordHasher : ITransientDependency
179{
180 string HashPassword(string password);
181 bool VerifyPassword(string password, string hash);
182}
183 
184// ✅ 存储提供器工厂(每次创建新实例)
185public interface IStorageProviderFactory : ITransientDependency
186{
187 IStorageProvider CreateProvider(string providerType);
188}
189 
190// ✅ 配置变更通知器
191public interface IConfigChangeNotifier : ITransientDependency
192{
193 Task NotifyChangeAsync(string configKey);
194}
195```
196 
197## Scrutor 自动注册扩展方法
198 
199### 基础注册方法
200 
201```csharp
202// 位于 CodeSpirit.Shared.DependencyInjection.ServiceCollectionExtensions
203 
204// 自动扫描并注册标记接口的服务
205services.AddDependencyInjectionWithScrutor(Assembly.GetExecutingAssembly());
206 
207// 可同时扫描多个程序集
208services.AddDependencyInjectionWithScrutor(
209 Assembly.GetExecutingAssembly(),
210 typeof(SharedService).Assembly);
211```
212 
213### 高级注册方法
214 
215```csharp
216// 按命名约定自动注册(Service、Repository 后缀)
217services.AddAdvancedDependencyInjection(Assembly.GetExecutingAssembly());
218```
219 
220### 装饰器模式
221 
222```csharp
223// 使用装饰器包装现有服务
224services.AddDecorator<IUserService, CachingUserServiceDecorator>();
225services.AddDecorator<ILogger<UserService>, AuditLoggerDecorator<UserService>>();
226```
227 
228## 注册行为
229 
230Scrutor 自动完成以下注册:
231 
2321. **接口注册**:服务注册为其实现的业务接口
2332. **自身注册**:服务同时注册为自身类型(可直接注入具体类)
234 
235```csharp
236// 给定服务类
237public class UserService : IUserService, IScopedDependency { }
238 
239// Scrutor 自动注册:
240// services.AddScoped<IUserService, UserService>(); // 接口注册
241// services.AddScoped<UserService>(); // 自身注册
242 
243// 两种方式都可以注入:
244public class UserController
245{
246 public UserController(
247 IUserService userService, // ✅ 接口注入
248 UserService userServiceImpl) // ✅ 具体类注入
249 { }
250}
251```
252 
253## API 配置类中的服务注册
254 
255### 自动注册(BaseApiConfiguration 已处理)
256 
257```csharp
258public class ExamApiConfiguration : BaseApiConfiguration
259{
260 public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
261 {
262 base.ConfigureServices(services, configuration);
263
264 // Scrutor 自动注册已在 BaseApiConfiguration 中完成
265 // 无需再调用 AddDependencyInjectionWithScrutor
266 }
267}
268```
269 
270### 手动注册特殊服务
271 
272```csharp
273public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
274{
275 base.ConfigureServices(services, configuration);
276
277 // 手动注册:特殊配置、外部库服务、条件注册
278 services.AddScoped<ISpecialService>(sp =>
279 new SpecialService(sp.GetRequiredService<IOptions<SpecialOptions>>()));
280
281 // 注册外部库服务
282 services.AddHttpClient<IExternalApiClient, ExternalApiClient>();
283
284 // 条件注册
285 if (configuration.GetValue<bool>("Features:EnableNewFeature"))
286 {
287 services.AddScoped<INewFeatureService, NewFeatureService>();
288 }
289}
290```
291 
292## 依赖注入最佳实践
293 
294### ✅ 推荐做法
295 
296```csharp
297// 1. 构造函数注入(推荐)
298public class QuestionService : IQuestionService, IScopedDependency
299{
300 private readonly IRepository<Question> _repository;
301 private readonly IMapper _mapper;
302
303 public QuestionService(IRepository<Question> repository, IMapper mapper)
304 {
305 _repository = repository;
306 _mapper = mapper;
307 }
308}
309 
310// 2. 接口定义继承标记接口
311public interface IExamService : IScopedDependency
312{
313 Task<ExamDto> GetByIdAsync(long id);
314}
315 
316// 3. 使用 IServiceProvider 延迟解析(避免循环依赖)
317public class CrudDialogHandler : IScopedDependency
318{
319 private readonly IServiceProvider _serviceProvider;
320
321 public CrudDialogHandler(IServiceProvider serviceProvider)
322 {
323 _serviceProvider = serviceProvider;
324 }
325
326 private ColumnHelper ColumnHelper => _serviceProvider.GetRequiredService<ColumnHelper>();
327}
328```
329 
330### ❌ 禁止做法
331 
332```csharp
333// 1. 不要手动注册标记接口的服务(会重复注册)
334services.AddScoped<IUserService, UserService>(); // ❌ Scrutor 已自动注册
335 
336// 2. 不要使用服务定位器反模式
337public class BadService
338{
339 public void DoWork()
340 {
341 var service = ServiceLocator.GetService<IOtherService>(); // ❌
342 }
343}
344 
345// 3. 不要在 Singleton 服务中注入 Scoped 服务
346public class BadSingletonService : ISingletonDependency
347{
348 private readonly IUserService _userService; // ❌ Scoped 服务不能注入到 Singleton
349}
350 
351// 4. 不要创建多余的包装接口
352public interface IUserServiceWrapper : IUserService { } // ❌ 不必要
353```
354 
355## 常见问题
356 
357### 循环依赖处理
358 
359```csharp
360// 使用 IServiceProvider 延迟解析
361public class ServiceA : IScopedDependency
362{
363 private readonly IServiceProvider _serviceProvider;
364
365 public ServiceA(IServiceProvider serviceProvider)
366 {
367 _serviceProvider = serviceProvider;
368 }
369
370 // 延迟获取依赖
371 private IServiceB ServiceB => _serviceProvider.GetRequiredService<IServiceB>();
372}
373```
374 
375### 条件服务注册
376 
377```csharp
378// 在 API 配置类中进行条件注册
379public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
380{
381 base.ConfigureServices(services, configuration);
382
383 var storageType = configuration["Storage:Type"];
384 services.AddScoped<IStorageService>(sp => storageType switch
385 {
386 "S3" => sp.GetRequiredService<S3StorageService>(),
387 "Azure" => sp.GetRequiredService<AzureBlobStorageService>(),
388 _ => sp.GetRequiredService<LocalStorageService>()
389 });
390}
391```
392 
393### 多实现注册
394 
395```csharp
396// 注册多个实现
397services.AddScoped<INotificationService, EmailNotificationService>();
398services.AddScoped<INotificationService, SmsNotificationService>();
399 
400// 注入所有实现
401public class NotificationManager
402{
403 private readonly IEnumerable<INotificationService> _notificationServices;
404
405 public NotificationManager(IEnumerable<INotificationService> notificationServices)
406 {
407 _notificationServices = notificationServices;
408 }
409
410 public async Task NotifyAllAsync(string message)
411 {
412 foreach (var service in _notificationServices)
413 {
414 await service.SendAsync(message);
415 }
416 }
417}
418```
419 
420## 命名空间引用
421 
422```csharp
423using CodeSpirit.Core.DependencyInjection; // 标记接口
424using CodeSpirit.Shared.DependencyInjection; // 扩展方法
425```
426 

Sections

  • 依赖注入规范(Scrutor 自动注册)
  • 概述
  • 标记接口
  • 生命周期说明
  • 标记方式
  • 方式一:接口继承标记接口(推荐)
  • 方式二:实现类标记接口
  • 方式三:同时实现业务接口和标记接口
  • 生命周期选择指南
  • IScopedDependency(作用域 - 最常用)
  • ISingletonDependency(单例)
  • ITransientDependency(瞬时)
  • Scrutor 自动注册扩展方法
  • 基础注册方法
  • 高级注册方法
  • 装饰器模式
  • 注册行为
  • API 配置类中的服务注册
  • 自动注册(BaseApiConfiguration 已处理)
  • 手动注册特殊服务
  • 依赖注入最佳实践
  • ✅ 推荐做法
  • ❌ 禁止做法
  • 常见问题
  • 循环依赖处理
  • 条件服务注册
  • 多实现注册
  • 命名空间引用

What it covers

api

Stack — with the evidence

csharp

(1.00)

react

(0.70)

typescript

(0.60)

dotnet

(0.60)

kubernetes

(0.60)

github-actions

(0.60)

javascript

(0.50)

Glob targeting

  • *Service.cs
  • **/Services/**/*.cs
  • **/*Seeder*.cs
  • **/*Helper*.cs
  • **/*Handler*.cs
  • **/*Repository*.cs

Format

Cursor rules

The most expressive format here. Many small .mdc files, each with frontmatter declaring when it should load, so a rule about migrations only enters context when a migration is open. Costs the most to maintain and only one editor reads it.

What the corpus says about it

Repository

Owner
xin-lai
Language
—
License
—
Archived
no

All configs in this repo

Also in xin-lai/CodeSpirit

Diff this repo’s formats

One 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?

The other instruction files in this repository
RepositoryFormatStackCoversScoreChanged
xin-lai/CodeSpirit.cursor/rules/js.mdc · 56Cursor rulescsharpreact+5apidocs46/1003 days ago
xin-lai/CodeSpirit.cursor/rules/ai-development.mdc · 56Cursor rulescsharpreact+5api46/1003 days ago
xin-lai/CodeSpirit.cursor/rules/all.mdc · 56Cursor rulescsharpreact+5testing-strategyapi50/1003 days ago
xin-lai/CodeSpirit.cursor/rules/amis-cards.mdc · 56Cursor rulescsharpreact+5no sections54/1003 days ago
xin-lai/CodeSpirit.cursor/rules/api-design.mdc · 56Cursor rulescsharpreact+5no sections54/1003 days ago
xin-lai/CodeSpirit.cursor/rules/controller.mdc · 56Cursor rulescsharpreact+5api54/1003 days ago
xin-lai/CodeSpirit.cursor/rules/cs.mdc · 56Cursor rulescsharpreact+5no sections25/1003 days ago
xin-lai/CodeSpirit.cursor/rules/csproj.mdc · 56Cursor rulescsharpreact+5api54/1003 days ago
xin-lai/CodeSpirit.cursor/rules/css.mdc · 56Cursor rulescsharpreact+5ui54/1003 days ago
xin-lai/CodeSpirit.cursor/rules/database.mdc · 56Cursor rulescsharpreact+5no sections74/1003 days ago
xin-lai/CodeSpirit.cursor/rules/dto.mdc · 56Cursor rulescsharpreact+5no sections50/1003 days ago
xin-lai/CodeSpirit.cursor/rules/enum.mdc · 56Cursor rulescsharpreact+5no sections50/1003 days ago
xin-lai/CodeSpirit.cursor/rules/i18n.mdc · 56Cursor rulescsharpreact+5no sections50/1003 days ago
xin-lai/CodeSpirit.cursor/rules/naming-conventions.mdc · 56Cursor rulescsharpreact+5no sections50/1003 days ago
xin-lai/CodeSpirit.cursor/rules/package-management.mdc · 56Cursor rulescsharpreact+5no sections74/1003 days ago
xin-lai/CodeSpirit.cursor/rules/performance.mdc · 56Cursor rulescsharpreact+5no sections54/1003 days ago
xin-lai/CodeSpirit.cursor/rules/project-structure.mdc · 56Cursor rulescsharpreact+5api54/1003 days ago
xin-lai/CodeSpirit.cursor/rules/security.mdc · 56Cursor rulescsharpreact+5database54/1003 days ago
xin-lai/CodeSpirit.cursor/rules/service.mdc · 56Cursor rulescsharpreact+5no sections50/1003 days ago
xin-lai/CodeSpirit.cursor/rules/startup-framework.mdc · 56Cursor rulescsharpreact+5api54/1003 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/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 Diff against .cursor/rules/startup-framework.mdc

Similar configs

Same format, overlapping stack, ranked by quality.

Same format, overlapping stack, ranked by quality
RepositoryFormatStackCoversScoreChanged
hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126Cursor rulesgobun+5setupbuildtestlint-format+6100/1003 days ago
TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45Cursor rulestypescriptpytest+15testlint-formatstylearch+5100/1003 days ago
markstev/mark-starter.cursor/rules/frontend.mdc · 0Cursor rulestypescriptturborepo+14setuptestlint-formatstyle+699/1003 days ago
Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0Cursor rulestypescriptturborepo+13setuptestlint-formatstyle+799/1003 days ago
deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1Cursor rulestypescriptnextjs+5setuptestlint-formatstyle+799/1003 days ago
dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0Cursor rulestypescriptturborepo+15setuptestlint-formatstyle+799/1003 days ago
langflow-ai/langflow.cursor/rules/docs_development.mdc · 153kCursor rulespythonnode+16setupbuildtestlint-format+797/1003 days ago
TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45Cursor rulestypescriptpytest+15teststyletesting-strategysecurity+397/1003 days ago
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack