このクイック スタートでは、 ServiceCollection とそれに対応する ServiceProviderを手動で作成する .NET コンソール アプリを作成します。 依存関係の挿入 (DI) を使用して、サービスを登録して解決する方法について説明します。 この記事では、 Microsoft.Extensions.DependencyInjection NuGet パッケージを使用して、.NET の DI の基本を示します。
注
この記事では、 汎用ホスト 機能を利用しません。 より包括的なガイドについては、「 .NET での依存関係の挿入の使用」を参照してください。
概要
開始するには、 DI.Basics という名前の新しい .NET コンソール アプリケーションを作成します。 Visual Studio で、[ ファイル] > [新しい > プロジェクト] を選択するか、 .NET CLI を使用して「 dotnet new console」と入力します。
次に、プロジェクト ファイル内の Microsoft.Extensions.DependencyInjection へのパッケージ参照を追加します。 パッケージを追加した後、プロジェクトが DI.Basics.csproj ファイルの次の XML に似ていることを確認します。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
</ItemGroup>
</Project>
依存関係の挿入の基礎
依存関係の挿入は、ハードコーディングされた依存関係を削除し、アプリケーションの保守性とテスト性を高めるために使用できる設計パターンです。 DI は、クラスとその依存関係 の間で制御の反転 (IoC) を実現するための手法です。
Microsoft.Extensions.DependencyInjection.Abstractions NuGet パッケージは、.NET の DI の抽象化を定義します。
- IServiceCollection: サービス記述子のコレクションのコントラクトを定義します。
- IServiceProvider: サービス オブジェクトを取得するためのメカニズムを定義します。
- ServiceDescriptor: サービスの種類、実装、有効期間を持つサービスについて説明します。
.NET では、サービスを追加し、 IServiceCollectionで構成することで DI を管理します。 サービスを登録したら、 BuildServiceProvider メソッドを呼び出して、 IServiceProvider インスタンスをビルドします。
IServiceProviderは、登録されているすべてのサービスのコンテナーとして機能し、サービスの解決に使用します。
サンプル サービスを作成する
すべてのサービスが均等に作成されるわけではありません。 一部のサービスでは、サービス コンテナーがそれらを取得するたびに新しいインスタンスが必要になります (一時的)。他のサービスは、要求間で共有する (スコープ指定された) か、アプリの有効期間全体 (シングルトン) で共有する必要があります。 サービスの有効期間の詳細については、「サービスの 有効期間」を参照してください。
同様に、一部のサービスは具象型のみを公開し、他のサービスはインターフェイスと実装型の間のコントラクトとして表されます。 これらの概念を示すのに役立つサービスのバリエーションをいくつか作成します。
IConsole.csという名前 の 新しい C# ファイルを作成し、次のコードを追加します。
public interface IConsole
{
void WriteLine(string message);
}
このファイルは、IConsole 1 つのメソッドを公開するWriteLine インターフェイスを定義します。 次に、 DefaultConsole.cs という名前の新しい C# ファイルを作成し、次のコードを追加します。
internal sealed class DefaultConsole : IConsole
{
public bool IsEnabled { get; set; } = true;
void IConsole.WriteLine(string message)
{
if (IsEnabled is false)
{
return;
}
Console.WriteLine(message);
}
}
上記のコードは、 IConsole インターフェイスの既定の実装を表しています。
WriteLine メソッドは、IsEnabled プロパティに基づいて条件付きでコンソールに書き込みます。
ヒント
実装の名前付けは、開発チームが同意する必要がある選択肢です。
Default プレフィックスは、インターフェイスの既定の実装を示す一般的な規則ですが、必須ではありません。
次に、 IGreetingService.cs ファイルを作成し、次の C# コードを追加します。
public interface IGreetingService
{
string Greet(string name);
}
次に、DefaultGreetingService.csという名前 の 新しい C# ファイルを追加し、次のコードを追加します。
internal sealed class DefaultGreetingService(
IConsole console) : IGreetingService
{
public string Greet(string name)
{
var greeting = $"Hello, {name}!";
console.WriteLine(greeting);
return greeting;
}
}
上記のコードは、 IGreetingService インターフェイスの既定の実装を表しています。 サービスの実装には、プライマリ コンストラクター パラメーターとして IConsole が必要です。
Greet メソッド:
-
greetingを指定してnameを作成します。 -
WriteLineインスタンスでIConsoleメソッドを呼び出します。 - 呼び出し元に
greetingを返します。
DefaultGreetingService クラスは、サービス実装をsealして継承を防ぎ、internalを使用してアセンブリへのアクセスを制限できることを示しています。
作成する最後のサービスは 、FarewellService.cs ファイルです。 続行する前に、次の C# コードを追加します。
public class FarewellService(IConsole console)
{
public string SayGoodbye(string name)
{
var farewell = $"Goodbye, {name}!";
console.WriteLine(farewell);
return farewell;
}
}
FarewellServiceは、インターフェイスではなく具象型を表します。 コンシューマーがアクセスできるように、 public として宣言する必要があります。 他のサービス実装の種類をinternalおよびsealedとして宣言する場合とは異なり、このコード例は、すべてのサービスがインターフェイスである必要はないことを示しています。
Program クラスを更新する
Program.cs ファイルを開き、既存のコードを次の C# コードに置き換えます。
using Microsoft.Extensions.DependencyInjection;
// 1. Create the service collection.
var services = new ServiceCollection();
// 2. Register (add and configure) the services.
services.AddSingleton<IConsole>(
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
});
services.AddSingleton<IGreetingService, DefaultGreetingService>();
services.AddSingleton<FarewellService>();
// 3. Build the service provider from the service collection.
var serviceProvider = services.BuildServiceProvider();
// 4. Resolve the services that you need.
var greetingService = serviceProvider.GetRequiredService<IGreetingService>();
var farewellService = serviceProvider.GetRequiredService<FarewellService>();
// 5. Use the services
var greeting = greetingService.Greet("David");
var farewell = farewellService.SayGoodbye("David");
上記のコードは、次の方法を示しています。
- 新しい
ServiceCollectionインスタンスを作成します。 -
ServiceCollectionでサービスを登録して構成します。- 実装ファクトリ オーバーロードを使用した
IConsoleサービス。DefaultConsoleプロパティがIsEnabledに設定されたtrue型を返します。 -
IGreetingServiceサービスは、対応する実装型であるDefaultGreetingServiceを持っています。 - 具体的な型としての
FarewellServiceサービス。
- 実装ファクトリ オーバーロードを使用した
-
ServiceProviderからServiceCollectionをビルドします。 -
IGreetingServiceサービスとFarewellServiceサービスを解決します。 - 解決されたサービスを使用して、
Davidという名前の人に挨拶し、別れを告げる。
IsEnabledのDefaultConsoleプロパティをfalseに更新すると、GreetメソッドとSayGoodbyeメソッドは結果のメッセージをコンソールに書き込むのを省略します。 この変更は、IConsole サービスがアプリの動作に影響を与える依存関係としてIGreetingServiceおよびFarewellService サービスに挿入されることを示すのに役立ちます。
これらのサービスはすべてシングルトンとして登録されます。 このサンプルでは、 一時的 または スコープ指定された サービスとして登録する場合と同じように動作します。
Important
この例では、サービスの有効期間は関係ありません。 実際のアプリケーションでは、各サービスの有効期間を慎重に検討してください。
サンプル アプリを実行する
サンプル アプリを実行するには、Visual Studio または Visual Studio Code で F5 キーを押すか、ターミナルで dotnet run コマンドを実行します。 アプリが完了すると、次の出力が表示されます。
Hello, David!
Goodbye, David!
サービス記述子
ServiceCollectionにサービスを追加するために最も一般的に使用される API は、次のような有効期間名のジェネリック拡張メソッドです。
AddSingleton<TService>AddTransient<TService>AddScoped<TService>
これらのメソッドは、 ServiceDescriptor インスタンスを作成して ServiceCollectionに追加する便利なメソッドです。
ServiceDescriptorは、サービスの種類、実装の種類、有効期間を持つサービスを記述する単純なクラスです。 また、実装ファクトリとインスタンスについても説明できます。
ServiceCollectionに登録したサービスごとに、代わりに Add インスタンスを使用して ServiceDescriptor メソッドを直接呼び出します。 次の例を考えてみましょう。
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IConsole),
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
},
lifetime: ServiceLifetime.Singleton));
上記のコードは、 IConsole サービスが ServiceCollectionに登録された方法と同じです。
Add メソッドは、ServiceDescriptor サービスを記述するIConsole インスタンスを追加します。 静的メソッドは、さまざまなコンストラクターServiceDescriptor.Describeに委任します。
IGreetingService サービスの同等のコードを考えてみましょう。
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IGreetingService),
implementationType: typeof(DefaultGreetingService),
lifetime: ServiceLifetime.Singleton));
前のコードでは、 IGreetingService サービスとそのサービスの種類、実装の種類、有効期間について説明します。 最後に、 FarewellService サービスの同等のコードを検討します。
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(FarewellService),
implementationType: typeof(FarewellService),
lifetime: ServiceLifetime.Singleton));
上記のコードでは、具体的な FarewellService 型をサービス型と実装型の両方として記述します。 サービスはシングルトン サービスとして登録されます。
こちらも参照ください
- .NET の依存関係の挿入
- 依存関係の挿入のガイドライン
- ASP.NET Core における依存関係の注入
.NET