サービスのライフタイム:Transient、Scoped、Singleton
Transient、Scoped、Singletonのライフタイムが、オブジェクトの生成、共有、破棄にどのような影響を与えるかを学びます。
「サービスのライフタイム:Transient、Scoped、Singleton」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。
ライフタイムが重要な理由
サービスのライフタイムは、インスタンスが存続する期間と作成されるインスタンス数を制御します。誤ったライフタイムを選ぶと、リクエスト間でのデータ漏洩や過剰なオブジェクト生成など、見つけにくいバグの原因になります。
Transient: 毎回新しく作成
Transientサービスは、コンテナーから要求されるたびに新しく作成されます。状態を共有すると危険な、軽量でステートレスなサービスに使用してください。
builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();
// Each resolution creates a new instance:
// var a = sp.GetRequiredService<IEmailSender>(); // new
// var b = sp.GetRequiredService<IEmailSender>(); // new (different)Scoped: リクエストごとに1回
Scopedサービスは、スコープごとに1回作成されます。ASP.NET Coreでは通常、1つのHTTPリクエストが1つのスコープに対応します。同じインスタンスがリクエスト内で共有され、次のリクエストでは新しいインスタンスが作成されます。
builder.Services.AddScoped<AppDbContext>();
// Within a single HTTP request:
// Both resolve to the SAME AppDbContext instance
// -> consistent unit of work across the requestSingleton: アプリケーションのライフタイム全体で1つ
Singletonサービスは1回だけ作成され、アプリケーションのライフタイム全体で再利用されます。設定キャッシュのように、作成コストが高くスレッドセーフなサービスに使用してください。
builder.Services.AddSingleton<IMemoryCache, MemoryCache>();
// Or register a pre-built instance:
var config = new AppConfig { MaxRetries = 3 };
builder.Services.AddSingleton<IAppConfig>(config);3つのライフタイムの比較
簡単に比較すると、次のようになります。
- Transient — 要求ごとに新しいインスタンス。ステートレスなユーティリティ
- Scoped — HTTPリクエストごとに1つ。DbContext、Unit of Work
- Singleton — アプリケーションのライフタイム全体で1つ。キャッシュ、設定
キャプティブ依存関係の問題
ScopedまたはTransientサービスをSingletonに注入するのは、よくある間違いです。Singletonが短命なサービスへの参照を保持するため、そのサービスが必要以上に長く存続してしまいます。
// BAD: Singleton captures a Scoped service
public class MySingleton
{
private readonly AppDbContext _db; // Scoped!
public MySingleton(AppDbContext db) => _db = db;
// _db is now stuck alive for the app's lifetime
}スコープ違反の検出
ValidateScopesを有効にすると、キャプティブ依存関係が検出された場合に、コンテナーが起動時に例外をスローします。これにより、本番環境でデータに関するバグが発生する前にミスを見つけられます。
builder.Host.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = true; // detect captive deps
options.ValidateOnBuild = true; // fail fast at start
});リクエスト外でのScopedサービス
バックグラウンドタスクでScopedサービスを解決するには、IServiceScopeFactoryを使用して明示的なスコープを作成します。ルートコンテナーからScopedサービスを直接解決してはいけません。
public class MyWorker : BackgroundService
{
private readonly IServiceScopeFactory _factory;
public MyWorker(IServiceScopeFactory factory) => _factory = factory;
protected override async Task ExecuteAsync(CancellationToken ct)
{
using var scope = _factory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await db.Users.ToListAsync(ct);
}
}Transientの破棄可能サービス
ルートコンテナーから解決されたTransientのIDisposableサービスは、コンテナーが破棄されるまで(アプリケーションの終了時まで)追跡されます。リソースを速やかに解放するには、スコープ内で解決してください。
// Correctly scoped transient disposable
using var scope = sp.CreateScope();
var svc = scope.ServiceProvider.GetRequiredService<MyDisposableService>();
await svc.DoWorkAsync();
// svc.Dispose() called when scope is disposed適切なライフタイムの選択
簡単な判断ガイド:
- サービスはステートレスですか。→ Transient
- リクエストに依存しますか(ユーザーのIDやDbContextなど)。→ Scoped
- スレッドセーフで、構築コストが高いですか。→ Singleton
実践例: 3つのライフタイムの併用
一般的なWeb APIでは、正確性とパフォーマンスを保つため、各サービスを適切なライフタイムで登録します。
builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
builder.Services.AddSingleton<ICacheService, RedisCacheService>();
builder.Services.AddScoped<AppDbContext>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<OrderService>();
builder.Services.AddTransient<IEmailSender, SendGridEmailSender>();クイックチェック
SingletonサービスがScopedサービスへの参照を保持すると、どのような問題が発生しますか。
まとめ: サービスのライフタイム
重要なポイント:
- Transient: 毎回新しいインスタンス。ステートレスで軽量なサービスに適しています
- Scoped: リクエストごとに1つのインスタンス。DbContext、リポジトリ、Unit of Workに適しています
- Singleton: アプリケーションのライフタイム全体で1つのインスタンス。キャッシュ、設定、スレッドセーフなユーティリティに適しています
- 短命なサービスを、より長命なサービスに注入してはいけません(キャプティブ依存関係)
- バックグラウンドタスクでScopedサービスを解決するには
IServiceScopeFactoryを使用します
よくある質問
「サービスのライフタイム:Transient、Scoped、Singleton」レッスンは無料ですか?
はい。「サービスのライフタイム:Transient、Scoped、Singleton」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。
「サービスのライフタイム:Transient、Scoped、Singleton」で何を学びますか?
Transient、Scoped、Singletonのライフタイムが、オブジェクトの生成、共有、破棄にどのような影響を与えるかを学びます。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C# Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「サービスのライフタイム:Transient、Scoped、Singleton」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC# Academyレッスンでコードを書いて実行できますか?
はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- DIコンテナーの基礎
- サービスのライフタイム:Transient、Scoped、Singleton
- コンストラクターインジェクションとインターフェース
- FactoryとOptionsパターン