Communityコーディング&開発github.com

依存性注入パターン

IServiceCollection拡張メソッドを使用してDI登録を整理します。関連するサービスを構成可能なAdd*メソッドにグループ化し、Program.csをクリーンに保ち、テストでの設定を再利用可能にします。

依存性注入パターン とは?

このスキルは、ASP.NET Coreアプリケーションにおける依存性注入(DI)登録を整理するためのパターンを提供します。Program.csやStartup.csが数百行に及ぶサービス登録で肥大化する問題を解決するため、IServiceCollectionの拡張メソッドを使用して関連するサービスをグループ化し、`AddUserServices()` や `AddOrderServices()` のような構成可能なAdd*メソッドを作成します。このアプローチにより、Program.csがクリーンになり、登録の境界が明確になり、テストでも本番と同じ設定を再利用できるようになります。さらに、階層的な拡張メソッド構成、Akka.NETアクター設定、ライフタイム管理(シングルトン、スコープ、トランジェント)のベストプラクティス、スコープサービスをシングルトンに注入するなどのアンチパターンもカバーしています。対応プラットフォームはASP.NET Core、Akka.Hosting、および `Microsoft.Extensions.DependencyInjection` を使用する任意のアプリケーションです。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Aaronontheweb/dotnet-skills/tree/main/skills/microsoft-extensions-dependency-injection

Installed? Explore more コーディング&開発 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

依存性注入パターン は何をしますか?

このスキルを使用するタイミング

以下の場合にこのスキルを使用します:

  • ASP.NET Coreアプリケーションでサービス登録を整理する場合
  • 数百行もの登録がある巨大なProgram.cs/Startup.csファイルを避ける場合
  • 本番環境とテスト間でサービス設定を再利用可能にする場合
  • Microsoft.Extensions.DependencyInjection と統合するライブラリを設計する場合

参考ファイル

  • advanced-patterns.md: DI拡張を使用したテスト、Akka.NETアクタースコープ管理、条件付き/ファクトリ/キー付き登録パターン

問題点

整理されていない場合、Program.csは管理不能になります:

// 悪い例: 200行以上の整理されていない登録
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddScoped<IUserService, UserService>();
// ... さらに150行 ...

問題点: 関連する登録を見つけにくい、明確な境界がない、テストで再利用できない、マージコンフリクトが発生する。


解決策: 拡張メソッドによる構成

関連する登録を拡張メソッドにグループ化します:

// 良い例: クリーンで構成可能なProgram.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddUserServices()
    .AddOrderServices()
    .AddEmailServices()
    .AddPaymentServices()
    .AddValidators();

var app = builder.Build();

拡張メソッドパターン

基本構造

namespace MyApp.Users;

public static class UserServiceCollectionExtensions
{
    public static IServiceCollection AddUserServices(this IServiceCollection services)
    {
        services.AddScoped<IUserRepository, UserRepository>();
        services.AddScoped<IUserReadStore, UserReadStore>();
        services.AddScoped<IUserWriteStore, UserWriteStore>();
        services.AddScoped<IUserService, UserService>();
        services.AddScoped<IUserValidationService, UserValidationService>();

        return services;
    }
}

設定を受け取る場合

namespace MyApp.Email;

public static class EmailServiceCollectionExtensions
{
    public static IServiceCollection AddEmailServices(
        this IServiceCollection services,
        string configSectionName = "EmailSettings")
    {
        services.AddOptions<EmailOptions>()
            .BindConfiguration(configSectionName)
            .ValidateDataAnnotations()
            .ValidateOnStart();

        services.AddSingleton<IMjmlTemplateRenderer, MjmlTemplateRenderer>();
        services.AddSingleton<IEmailLinkGenerator, EmailLinkGenerator>();
        services.AddScoped<IUserEmailComposer, UserEmailComposer>();
        services.AddScoped<IEmailSender, SmtpEmailSender>();

        return services;
    }
}

ファイル構成

拡張メソッドは、登録するサービスの近くに配置します:

src/
  MyApp.Api/
    Program.cs                    # すべてのAdd*メソッドを構成
  MyApp.Users/
    Services/
      UserService.cs
    UserServiceCollectionExtensions.cs   # AddUserServices()
  MyApp.Orders/
    OrderServiceCollectionExtensions.cs  # AddOrderServices()
  MyApp.Email/
    EmailServiceCollectionExtensions.cs  # AddEmailServices()

命名規則: {機能名}ServiceCollectionExtensions.cs をその機能のサービスの隣に配置します。


命名規則

パターン使用目的
Add{機能名}Services()一般的な機能登録
Add{機能名}()曖昧さがない場合の短縮形
Configure{機能名}()主にオプション設定時
Use{機能名}()ミドルウェア(IApplicationBuilder)

テストの利点

Add* パターンにより、テストで本番設定を再利用し、異なる部分だけを上書きできます。WebApplicationFactory、Akka.Hosting.TestKit、スタンドアロンのServiceCollectionで動作します。

詳細なテスト例は advanced-patterns.md を参照してください。


階層的な拡張

大規模アプリケーションでは、拡張メソッドを階層的に構成します:

public static class AppServiceCollectionExtensions
{
    public static IServiceCollection AddAppServices(this IServiceCollection services)
    {
        return services
            .AddDomainServices()
            .AddInfrastructureServices()
            .AddApiServices();
    }
}

public static class DomainServiceCollectionExtensions
{
    public static IServiceCollection AddDomainServices(this IServiceCollection services)
    {
        return services
            .AddUserServices()
            .AddOrderServices()
            .AddProductServices();
    }
}

Akka.Hosting 統合

同じパターンはAkka.NETアクター設定にも適用できます:

public static class OrderActorExtensions
{
    public static AkkaConfigurationBuilder AddOrderActors(
        this AkkaConfigurationBuilder builder)
    {
        return builder
            .WithActors((system, registry, resolver) =>
            {
                var orderProps = resolver.Props<OrderActor>();
                var orderRef = system.ActorOf(orderProps, "orders");
                registry.Register<OrderActor>(orderRef);
            });
    }
}

// Program.cs での使用例
builder.Services.AddAkka("MySystem", (builder, sp) =>
{
    builder
        .AddOrderActors()
        .AddInventoryActors()
        .AddNotificationActors();
});

完全なAkka.Hostingパターンについては akka-hosting-actor-patterns スキルを参照してください。


アンチパターン

避けるべき: Program.cs にすべてを登録する

// 悪い例: 200行以上の登録がある巨大なProgram.cs

避けるべき: 過度に汎用的な拡張メソッドを作成する

// 悪い例: 曖昧すぎて何が登録されるかわからない
public static IServiceCollection AddServices(this IServiceCollection services) { ... }

避けるべき: 重要な設定を隠す

// 悪い例: 設定が埋もれている
public static IServiceCollection AddDatabase(this IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseSqlServer("ハードコードされた接続文字列"));  // 隠れている!
}

// 良い例: 設定を明示的に受け取る
public static IServiceCollection AddDatabase(
    this IServiceCollection services,
    string connectionString)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseSqlServer(connectionString));
}

ベストプラクティスまとめ

実践利点
関連するサービスを Add* メソッドにグループ化クリーンなProgram.cs、明確な境界
拡張メソッドを登録するサービスの近くに配置見つけやすく、保守しやすい
メソッドチェーンのために IServiceCollection を返す流暢なAPI
設定パラメータを受け取る柔軟性
一貫した命名(Add{機能名}Services)を使用発見可能性
本番拡張メソッドを再利用してテスト信頼性、重複削減

ライフタイム管理

ライフタイム使用するタイミング例
シングルトンステートレス、スレッドセーフ、生成コストが高い設定、HttpClientファクトリ、キャッシュ
スコープリクエストごとにステートフル、データベースコンテキストDbContext、リポジトリ、ユーザーコンテキスト
トランジェント軽量、ステートフルだが生成コストが低いバリデーター、短命のヘルパー
// シングルトン: ステートレスなサービス、安全に共有可能
services.AddSingleton<IMjmlTemplateRenderer, MjmlTemplateRenderer>();

// スコープ: データベースアクセス、リクエストごとの状態
services.AddScoped<IUserRepository, UserRepository>();

// トランジェント: 軽量、短命
services.AddTransient<CreateUserRequestValidator>();

スコープサービスにはスコープが必要です。 ASP.NET CoreはHTTPリクエストごとにスコープを作成します。バックグラウンドサービスやアクターでは、手動でスコープを作成します。

アクタースコープ管理パターンについては advanced-patterns.md を参照してください。


よくある間違い

スコープサービスをシングルトンに注入する

// 悪い例: シングルトンがスコープサービスをキャプチャ - 古いDbContextに!
public class CacheService  // シングルトンとして登録
{
    private readonly IUserRepository _repo;  // スコープ - 起動時にキャプチャ!
}

// 良い例: IServiceProviderを注入し、操作ごとにスコープを作成
public class CacheService
{
    private readonly IServiceProvider _serviceProvider;

    public async Task<User> GetUserAsync(string id)
    {
        using var scope = _serviceProvider.CreateScope();
        var repo = scope.ServiceProvider.GetRequiredService<IUserRepository>();
        return await repo.GetByIdAsync(id);
    }
}

バックグラウンド処理でスコープを作成しない

// 悪い例: スコープサービスのためのスコープがない
public class BadBackgroundService : BackgroundService
{
    private readonly IOrderService _orderService;  // スコープ - 例外が発生する!
}

// 良い例: 処理単位ごとにスコープを作成
public class GoodBackgroundService : BackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory;

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        using var scope = _scopeFactory.CreateScope();
        var orderService = scope.ServiceProvider.GetRequiredService<IOrderService>();
        // ...
    }
}

リソース

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

akka-hosting-actor-patterns

Patterns for building entity actors with Akka.Hosting - GenericChildPerEntityParent, message extractors, cluster sharding abstraction, akka-reminders, and ITimeProvider. Supports both local testing and clustered production modes.

akka-net-aspire-configuration

Configure Akka.NET with .NET Aspire for local development and production deployments. Covers actor system setup, clustering, persistence, Akka.Management integration, and Aspire orchestration patterns.

akka-net-best-practices

Critical Akka.NET best practices including EventStream vs DistributedPubSub, supervision strategies, error handling, Props vs DependencyResolver, work distribution patterns, and cluster/local mode abstractions for testability.

akka-net-management

Akka.Management for cluster bootstrapping, service discovery (Kubernetes, Azure, Config), health checks, and dynamic cluster formation without static seed nodes.

akka-net-testing-patterns

Write unit and integration tests for Akka.NET actors using modern Akka.Hosting.TestKit patterns. Covers dependency injection, TestProbes, persistence testing, and actor interaction verification. Includes guidance on when to use traditional TestKit.

api-design

Design stable, compatible public APIs using extend-only design principles. Manage API compatibility, wire compatibility, and versioning for NuGet packages and distributed systems.

aspire-configuration

Configure Aspire AppHost to emit explicit app config via environment variables; keep app code free of Aspire clients and service discovery.

aspire-integration-testing

Write integration tests using .NET Aspire

aspire-service-defaults

Create a shared ServiceDefaults project for Aspire applications. Centralizes OpenTelemetry, health checks, resilience, and service discovery configuration across all services.

crap-analysis

Analyze code coverage and CRAP (Change Risk Anti-Patterns) scores to identify high-risk code. Use OpenCover format with ReportGenerator for Risk Hotspots showing cyclomatic complexity and untested code paths.

csharp-concurrency-patterns

Choosing the right concurrency abstraction in .NET - from async/await for I/O to Channels for producer/consumer to Akka.NET for stateful entity management. Avoid locks and manual synchronization unless absolutely necessary.

database-performance

Database access patterns for performance. Separate read/write models, avoid N+1 queries, use AsNoTracking, apply row limits, and never do application-side joins. Works with EF Core and Dapper.

dotnet-devcert-trust

Diagnose and fix .NET HTTPS dev certificate trust issues on Linux. Covers the full certificate lifecycle from generation to system CA bundle inclusion, with distro-specific guidance for Ubuntu, Fedora, Arch, and WSL2.

dotnet-local-tools

Managing local .NET tools with dotnet-tools.json for consistent tooling across development environments and CI/CD pipelines.

dotnet-project-structure

Modern .NET project structure including .slnx solution format, Directory.Build.props, central package management, SourceLink, version management with RELEASE_NOTES.md, and SDK pinning with global.json.

dotnet-slopwatch

Use Slopwatch to detect LLM reward hacking in .NET code changes. Run after every code modification to catch disabled tests, suppressed warnings, empty catch blocks, and other shortcuts that mask real problems.

efcore-patterns

Entity Framework Core best practices including NoTracking by default, query splitting for navigation collections, migration management, dedicated migration services, and common pitfalls to avoid.

ilspy-decompile

Understand implementation details of .NET code by decompiling assemblies. Use when you want to see how a .NET API works internally, inspect NuGet package source, view framework implementation, or understand compiled .NET binaries.

mailpit-integration

Test email sending locally using Mailpit with .NET Aspire. Captures all outgoing emails without sending them. View rendered HTML, inspect headers, and verify delivery in integration tests.

marketplace-publishing

Workflow for publishing skills and agents to the dotnet-skills Claude Code marketplace. Covers adding new content, updating plugin.json, validation, and release tagging.

関連スキル