ワンクリックで
dependency-injection
Use when registering services, choosing lifetimes, or implementing DI patterns like decorator or keyed services.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when registering services, choosing lifetimes, or implementing DI patterns like decorator or keyed services.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use when designing gRPC services, proto files, or adding gRPC-Web or JSON transcoding.
Use when writing async code, propagating CancellationTokens, or fixing async/await pitfalls.
Use when applying or enforcing C# coding style — namespaces, sealed classes, var usage, XML docs.
Use when applying modern C# idioms — records, pattern matching, primary constructors, collection expressions.
Use when selecting or implementing design patterns in C# — factory, builder, strategy, decorator, or mediator.
Use when implementing error handling with domain exceptions, ProblemDetails, or RpcException mapping.
| name | dependency-injection |
| description | Use when registering services, choosing lifetimes, or implementing DI patterns like decorator or keyed services. |
| when_to_use | Use when registering services, choosing lifetimes, or implementing DI patterns like decorator or keyed services. |
| metadata | {"category":"core","agent":"dotnet-architect"} |
IServiceCollection extension methods// Organize by layer or feature
public static class DependencyInjection
{
public static IServiceCollection AddApplicationServices(
this IServiceCollection services)
{
services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly));
services.AddValidatorsFromAssembly(
typeof(DependencyInjection).Assembly);
return services;
}
public static IServiceCollection AddInfrastructureServices(
this IServiceCollection services, IConfiguration configuration)
{
// Scoped — one instance per HTTP request
services.AddScoped<IOrderRepository, OrderRepository>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
// Open generics
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
// Singleton — one instance for the app lifetime
services.AddSingleton<IDateTimeProvider, DateTimeProvider>();
// Transient — new instance every time
services.AddTransient<IEmailSender, SmtpEmailSender>();
return services;
}
}
// Program.cs
builder.Services
.AddApplicationServices()
.AddInfrastructureServices(builder.Configuration);
Singleton — stateless services, caches, configuration wrappers
Example: IDateTimeProvider, HybridCache, IOptions<T>
Warning: must be thread-safe
Scoped — per-request state, DbContext, UnitOfWork, repositories
Example: AppDbContext, ICurrentUserService
Default choice for most services
Transient — lightweight stateless services, factory output
Example: IEmailSender, validators
Warning: do not hold expensive resources
// Registration
services.AddKeyedSingleton<IPaymentGateway, StripeGateway>("stripe");
services.AddKeyedSingleton<IPaymentGateway, PayPalGateway>("paypal");
services.AddKeyedSingleton<IPaymentGateway, SquareGateway>("square");
// Injection via attribute
public sealed class CheckoutService(
[FromKeyedServices("stripe")] IPaymentGateway gateway)
{
public Task ChargeAsync(decimal amount) => gateway.ChargeAsync(amount);
}
// Resolution from provider
public sealed class PaymentRouter(IServiceProvider provider)
{
public IPaymentGateway GetGateway(string name)
=> provider.GetRequiredKeyedService<IPaymentGateway>(name);
}
// Base service
services.AddScoped<IOrderService, OrderService>();
// Decorate with cross-cutting concerns (outermost last)
services.Decorate<IOrderService, CachedOrderService>();
services.Decorate<IOrderService, LoggingOrderService>();
// Decorator implementation
public sealed class CachedOrderService(
IOrderService inner,
HybridCache cache) : IOrderService
{
public async Task<Order?> GetOrderAsync(Guid id, CancellationToken ct)
{
return await cache.GetOrCreateAsync(
$"orders:{id}",
async token => await inner.GetOrderAsync(id, token),
cancellationToken: ct);
}
}
services.AddScoped<IReportGenerator>(sp =>
{
var config = sp.GetRequiredService<IOptions<ReportOptions>>().Value;
return config.Format switch
{
"pdf" => sp.GetRequiredService<PdfReportGenerator>(),
"csv" => sp.GetRequiredService<CsvReportGenerator>(),
_ => throw new InvalidOperationException(
$"Unknown report format: {config.Format}")
};
});
// Background services are singletons — create scopes for scoped deps
public sealed class OrderProcessor(
IServiceScopeFactory scopeFactory,
ILogger<OrderProcessor> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
using var scope = scopeFactory.CreateScope();
var repository = scope.ServiceProvider
.GetRequiredService<IOrderRepository>();
var unitOfWork = scope.ServiceProvider
.GetRequiredService<IUnitOfWork>();
await ProcessPendingOrdersAsync(repository, unitOfWork, ct);
await Task.Delay(TimeSpan.FromSeconds(30), ct);
}
}
}
// Strongly-typed options with validation
services.AddOptions<DatabaseOptions>()
.BindConfiguration(DatabaseOptions.SectionName)
.ValidateDataAnnotations()
.ValidateOnStart();
services.AddOptions<JwtOptions>()
.BindConfiguration("Jwt")
.ValidateDataAnnotations()
.ValidateOnStart();
// BAD: Service locator — hides dependencies
public class OrderService(IServiceProvider provider)
{
public void Process()
{
var repo = provider.GetRequiredService<IOrderRepository>();
}
}
// BAD: Captive dependency — scoped inside singleton
services.AddSingleton<MySingleton>(); // holds IOrderRepository (scoped)
// BAD: Resolving in constructor
public class OrderService(IServiceProvider provider)
{
private readonly IOrderRepository _repo =
provider.GetRequiredService<IOrderRepository>(); // resolves too early
}
// BAD: new-ing up services manually
public class OrderController
{
private readonly OrderService _service = new OrderService(
new OrderRepository(new AppDbContext())); // defeats DI
}
builder.Services.Add calls in Program.csIServiceCollection extension methods in the codebase[FromKeyedServices] usage (indicates .NET 8+ keyed DI)AddScoped, AddTransient, AddSingleton registration patternsIServiceScopeFactory usage in background servicesScrutor package (provides Decorate<> extension)builder.Services.Add* calls into extension methods per layerValidateOnStart() to all Options registrationsScrutor for decorator support if not already available:
<PackageReference Include="Scrutor" />
| Scenario | Lifetime | Notes |
|---|---|---|
| DbContext | Scoped | One per request |
| Repository | Scoped | Matches DbContext lifetime |
| HttpClient handler | Transient | Via IHttpClientFactory |
| Cache wrapper | Singleton | Thread-safe required |
| Options | Singleton | Via IOptions |
| Current user | Scoped | Per-request context |
| Background service | Singleton | Use IServiceScopeFactory inside |