Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Advanced Microsoft.Extensions.DependencyInjection patterns for .NET applications. Covers service lifetimes, keyed
services (net8.0+), decoration, factory delegates, scope validation, and hosted service registration.
Scope
Service lifetimes (transient, scoped, singleton) and captive dependency detection
Keyed services (.NET 8+) and factory delegates
Decorator pattern and scope validation
Hosted service registration
Out of scope
Async/await patterns in BackgroundService -- see [skill:dotnet-csharp-async-patterns]
Options pattern binding and IOptions -- see [skill:dotnet-csharp-configuration]
SOLID/DRY design principles -- see [skill:dotnet-solid-principles]
Cross-references: [skill:dotnet-csharp-async-patterns] for BackgroundService async patterns,
[skill:dotnet-csharp-configuration] for IOptions<T> binding.
Service Lifetimes
Lifetime
Registration
When to Use
Transient
AddTransient<T>()
Lightweight, stateless services. New instance per injection.
Scoped
AddScoped<T>()
Per-request state (EF Core DbContext, unit of work).
Singleton
AddSingleton<T>()
Thread-safe, stateless, or shared state (caches, config).
Lifetime Mismatches (Captive Dependencies)
Never inject a shorter-lived service into a longer-lived one:
// WRONG -- scoped DbContext captured in singleton = same context for all requests
builder.Services.AddSingleton<OrderService>(); // singleton
builder.Services.AddScoped<AppDbContext>(); // scoped -- CAPTIVE!// CORRECT -- use IServiceScopeFactory in singletonspublicsealedclassOrderService(IServiceScopeFactory scopeFactory)
{
publicasync Task ()
{
scope = scopeFactory.CreateScope();
db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Orders.Where(o => o.IsPending).ToListAsync(ct);
}
}
```text
```csharp
builder = WebApplication.CreateBuilder();
host = Host.CreateDefaultBuilder()
.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = ;
options.ValidateOnBuild = ;
})
.Build();
```text
---
```csharp
builder.Services.AddScoped<IOrderRepository, SqlOrderRepository>();
```csharp
```csharp
builder.Services.AddScoped<INotifier, EmailNotifier>();
builder.Services.AddScoped<INotifier, SmsNotifier>();
builder.Services.AddScoped<INotifier, PushNotifier>();
{
{
( notifier notifiers)
{
notifier.NotifyAsync(message, ct);
}
}
}
```text
```csharp
builder.Services.AddScoped<IOrderService>(sp =>
{
repo = sp.GetRequiredService<IOrderRepository>();
logger = sp.GetRequiredService<ILogger<OrderService>>();
options = sp.GetRequiredService<IOptions<OrderOptions>>();
OrderService(repo, logger, options.Value.MaxRetries);
});
```text
Libraries should use `TryAdd` so applications can :
```csharp
builder.Services.TryAddScoped<IOrderRepository, DefaultOrderRepository>();
builder.Services.AddScoped<IOrderRepository, CustomOrderRepository>();
```text
---
Register resolve services a key, replacing the need named service patterns.
```csharp
builder.Services.AddKeyedScoped<ICache, RedisCache>();
builder.Services.AddKeyedScoped<ICache, MemoryCache>();
{
Task<Order?> GetAsync( id, CancellationToken ct = )
{
localCache.GetAsync<Order>(id.ToString(), ct)
?? distributedCache.GetAsync<Order>(id.ToString(), ct);
}
}
cache = sp.GetRequiredKeyedService<ICache>();
```text
> **net8+ only.** On earlier TFMs, use factory patterns a dictionary-based approach.
---
The built- container does natively support decoration. Use one of these approaches:
```csharp
builder.Services.AddScoped<SqlOrderRepository>();
builder.Services.AddScoped<IOrderRepository>(sp =>
{
inner = sp.GetRequiredService<SqlOrderRepository>();
logger = sp.GetRequiredService<ILogger<LoggingOrderRepository>>();
LoggingOrderRepository(inner, logger);
});
{
Task<Order?> GetByIdAsync( id, CancellationToken ct = )
{
logger.LogInformation(, id);
inner.GetByIdAsync(id, ct);
}
}
```text
```csharp
builder.Services.AddScoped<IOrderRepository, SqlOrderRepository>();
builder.Services.Decorate<IOrderRepository, LoggingOrderRepository>();
builder.Services.Decorate<IOrderRepository, CachingOrderRepository>();
```text
---
```
{
{
logger.LogInformation();
(!stoppingToken.IsCancellationRequested)
{
{
scope = scopeFactory.CreateScope();
processor = scope.ServiceProvider
.GetRequiredService<IQueueProcessor>();
processor.ProcessNextBatchAsync(stoppingToken);
}
(Exception ex) (ex OperationCanceledException)
{
logger.LogError(ex, );
}
Task.Delay(TimeSpan.FromSeconds(), stoppingToken);
}
}
}
builder.Services.AddHostedService<QueueProcessorWorker>();
```text
```
{
{
scope = scopeFactory.CreateScope();
db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Database.MigrateAsync(cancellationToken);
logger.LogInformation();
}
=> Task.CompletedTask;
}
builder.Services.AddHostedService<DatabaseMigrationService>();
```text
- Always use `IServiceScopeFactory` to create scopes -- hosted services are singletons
- Never inject services directly hosted service constructors
- Handle exceptions inside `ExecuteAsync` --
{
{
services.AddScoped<IOrderRepository, SqlOrderRepository>();
services.AddScoped<IOrderService, OrderService>();
services.AddHostedService<OrderProcessorWorker>();
services;
}
{
services.AddScoped<INotifier, EmailNotifier>();
services.AddScoped<INotifier, SmsNotifier>();
services;
}
}
builder.Services.AddOrderServices();
builder.Services.AddNotificationServices();
```csharp
---
```csharp
[]
{
services = ServiceCollection();
services.AddScoped<IOrderRepository, InMemoryOrderRepository>();
services.AddScoped<IOrderService, OrderService>();
services.AddLogging();
provider = services.BuildServiceProvider();
scope = provider.CreateScope();
service = scope.ServiceProvider.GetRequiredService<IOrderService>();
order = service.GetByIdAsync();
Assert.NotNull(order);
}
```text
For unit tests, prefer direct constructor injection mocks rather than building a full container.
---
**Primary approach:** Use Serena symbol operations efficient code navigation:
**Find definitions**: `serena_find_symbol` instead of text search
**Understand structure**: `serena_get_symbols_overview` organization
**Track references**: `serena_find_referencing_symbols` impact analysis
**Precise edits**: `serena_replace_symbol_body` clean modifications
**When to use Serena vs traditional tools:**
- ✅ **Use Serena**: Navigation, refactoring, dependency analysis, precise edits
- ✅ **Use Read/Grep**: Reading full files, pattern matching, simple text operations
- ✅ **Fallback**: If Serena unavailable, traditional tools work fine
**Example workflow:**
```text
Read: src/Services/OrderService.cs
Grep:
serena_find_symbol:
serena_get_symbols_overview:
```
- [Dependency injection .NET](https:
- [Keyed services .NET ](https:
- [Background tasks hosted services](https:
- [Service lifetimes](https:
- [.NET Framework Design Guidelines](https:
ProcessAsync
CancellationToken ct = default
using
var
var
await
### Enable Scope Validation (Development)
var
args
// In Development, ValidateScopes is already true by default.
public Task StopAsync(CancellationToken cancellationToken)
### Key Rules for Hosted Services
scoped
into
unhandled exceptions stop the host (net8.0+)
- See [skill:dotnet-csharp-async-patterns] forasync patterns in background workers
---
## Organizing Registrations
Group related registrations into extension methods for clean `Program.cs`:
```csharp
// ServiceCollectionExtensions.cspublicstaticclass ServiceCollectionExtensions