ASP.NET Core での依存関係の挿入Dependency injection in ASP.NET Core

作成者: Kirk LarkinSteve SmithScott AddieBrandon DahlerBy Kirk Larkin, Steve Smith, Scott Addie, and Brandon Dahler

ASP.NET Core では依存関係の挿入 (DI) ソフトウェア設計パターンがサポートされています。これは、クラスとその依存関係の間で制御の反転 (IoC) を実現するための手法です。ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.

MVC コントローラー内部における依存関係の挿入に固有の情報については、ASP.NET Core でのコントローラーへの依存関係の挿入 をご覧ください。For more information specific to dependency injection within MVC controllers, see ASP.NET Core でのコントローラーへの依存関係の挿入.

Web アプリ以外のアプリケーションで依存関係の挿入を使用する方法の詳細については、「.NET での依存関係の挿入」を参照してください。For information on using dependency injection in applications other than web apps, see Dependency injection in .NET.

オプションとしての依存関係挿入の詳細については、「ASP.NET Core のオプション パターン」を参照してください。For more information on dependency injection of options, see ASP.NET Core のオプション パターン.

このトピックでは、ASP.NET Core での依存関係の挿入について説明します。This topic provides information on dependency injection in ASP.NET Core. 依存関係の挿入の使用に関する主なドキュメントは、「.NET での依存関係の挿入」に含まれています。The primary documentation on using dependency injection is contained in Dependency injection in .NET.

サンプル コードを表示またはダウンロードします (ダウンロード方法)。View or download sample code (how to download)

依存関係の挿入の概要Overview of dependency injection

"依存関係" とは、他のオブジェクトが依存するオブジェクトのことです。A dependency is an object that another object depends on. 他のクラスが依存している、次の WriteMessage メソッドを備えた MyDependency クラスを調べます。Examine the following MyDependency class with a WriteMessage method that other classes depend on:

public class MyDependency
{
    public void WriteMessage(string message)
    {
        Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
    }
}

クラスは、MyDependency クラスのインスタンスを作成して、その WriteMessage メソッドを使用することができます。A class can create an instance of the MyDependency class to make use of its WriteMessage method. 次の例で、MyDependency クラスは IndexModel クラスの依存関係です。In the following example, the MyDependency class is a dependency of the IndexModel class:

public class IndexModel : PageModel
{
    private readonly MyDependency _dependency = new MyDependency();

    public void OnGet()
    {
        _dependency.WriteMessage("IndexModel.OnGet created this message.");
    }
}

このクラスは MyDependency クラスを作成し、これに直接依存しています。The class creates and directly depends on the MyDependency class. コードの依存関係には、前の例のような問題が含まれ、次の理由から回避する必要があります。Code dependencies, such as in the previous example, are problematic and should be avoided for the following reasons:

  • MyDependency を別の実装で置き換えるには、IndexModel クラスを変更する必要があります。To replace MyDependency with a different implementation, the IndexModel class must be modified.
  • MyDependency が依存関係を含んでいる場合、これらは IndexModel クラスによって構成する必要があります。If MyDependency has dependencies, they must also be configured by the IndexModel class. 複数のクラスが MyDependency に依存している大規模なプロジェクトでは、構成コードがアプリ全体に分散するようになります。In a large project with multiple classes depending on MyDependency, the configuration code becomes scattered across the app.
  • このような実装では、単体テストを行うことが困難です。This implementation is difficult to unit test. アプリはモックまたはスタブの MyDependency クラスを使用する必要がありますが、この方法では不可能です。The app should use a mock or stub MyDependency class, which isn't possible with this approach.

依存関係の挿入は、次の方法によってこれらの問題に対応します。Dependency injection addresses these problems through:

  • 依存関係の実装を抽象化するための、インターフェイスまたは基底クラスの使用。The use of an interface or base class to abstract the dependency implementation.
  • サービス コンテナー内の依存関係の登録。Registration of the dependency in a service container. ASP.NET Core には、組み込みのサービス コンテナー IServiceProvider が用意されています。ASP.NET Core provides a built-in service container, IServiceProvider. サービスは通常、アプリの Startup.ConfigureServices メソッドに登録されています。Services are typically registered in the app's Startup.ConfigureServices method.
  • サービスを使用するクラスのコンストラクターへの、サービスの "挿入"。Injection of the service into the constructor of the class where it's used. 依存関係のインスタンスの作成、およびインスタンスが不要になったときの廃棄の役割を、フレームワークが担当します。The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed.

サンプル アプリでは、IMyDependency インターフェイスは、WriteMessage メソッドを定義します。In the sample app, the IMyDependency interface defines the WriteMessage method:

public interface IMyDependency
{
    void WriteMessage(string message);
}

このインターフェイスは、具象型 MyDependency によって実装されます。This interface is implemented by a concrete type, MyDependency:

public class MyDependency : IMyDependency
{
    public void WriteMessage(string message)
    {
        Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
    }
}

サンプル アプリにおいて、IMyDependency サービスは具象型 MyDependency を使用して登録されます。The sample app registers the IMyDependency service with the concrete type MyDependency. AddScoped メソッドによって、サービスは、1 つの要求の有効期間であるスコープ付き有効期間で登録されます。The AddScoped method registers the service with a scoped lifetime, the lifetime of a single request. サービスの有効期間については、このトピックの後半で説明します。Service lifetimes are described later in this topic.

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IMyDependency, MyDependency>();

    services.AddRazorPages();
}

サンプル アプリでは、IMyDependency サービスが要求され、WriteMessage メソッドを呼び出すために使用されます。In the sample app, the IMyDependency service is requested and used to call the WriteMessage method:

public class Index2Model : PageModel
{
    private readonly IMyDependency _myDependency;

    public Index2Model(IMyDependency myDependency)
    {
        _myDependency = myDependency;            
    }

    public void OnGet()
    {
        _myDependency.WriteMessage("Index2Model.OnGet");
    }
}

DI パターンを使用すると、コントローラーは次のようになります。By using the DI pattern, the controller:

  • 具象型 MyDependency は使用されず、実装される IMyDependency インターフェイスのみが使用されます。Doesn't use the concrete type MyDependency, only the IMyDependency interface it implements. これにより、コントローラーが使用する実装は、コントローラーを変更することなく、簡単に変更できるようになります。That makes it easy to change the implementation that the controller uses without modifying the controller.
  • MyDependency のインスタンスは作成されず、DI コンテナーによって作成されます。Doesn't create an instance of MyDependency, it's created by the DI container.

組み込みのログ API を使用すると、IMyDependency インターフェイスの実装を向上させることができます。The implementation of the IMyDependency interface can be improved by using the built-in logging API:

public class MyDependency2 : IMyDependency
{
    private readonly ILogger<MyDependency2> _logger;

    public MyDependency2(ILogger<MyDependency2> logger)
    {
        _logger = logger;
    }

    public void WriteMessage(string message)
    {
        _logger.LogInformation( $"MyDependency2.WriteMessage Message: {message}");
    }
}

更新された ConfigureServices メソッドでは、新しい IMyDependency の実装が登録されます。The updated ConfigureServices method registers the new IMyDependency implementation:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IMyDependency, MyDependency2>();

    services.AddRazorPages();
}

MyDependency2 は、コンストラクターで要求される ILogger<TCategoryName> によって異なります。MyDependency2 depends on ILogger<TCategoryName>, which it requests in the constructor. ILogger<TCategoryName> は、フレームワークで提供されるサービスです。ILogger<TCategoryName> is a framework-provided service.

依存関係の挿入をチェーン形式で使用することはよくあります。It's not unusual to use dependency injection in a chained fashion. 次に、要求されたそれぞれの依存関係が、それ自身の依存関係を要求します。Each requested dependency in turn requests its own dependencies. コンテナーによってグラフ内の依存関係が解決され、完全に解決されたサービスが返されます。The container resolves the dependencies in the graph and returns the fully resolved service. 解決する必要がある依存関係の集合的なセットは、通常、"依存関係ツリー"、"依存関係グラフ"、または "オブジェクト グラフ" と呼ばれます。The collective set of dependencies that must be resolved is typically referred to as a dependency tree, dependency graph, or object graph.

コンテナーでは、(ジェネリック) オープン型を活用し、すべての (ジェネリック) 構築型を登録する必要をなくすことで、ILogger<TCategoryName> を解決します。The container resolves ILogger<TCategoryName> by taking advantage of (generic) open types, eliminating the need to register every (generic) constructed type.

依存関係の挿入に関する用語では、サービスは次のようになります。In dependency injection terminology, a service:

  • 通常、他のオブジェクト (IMyDependency サービスなど) にサービスを提供するオブジェクトです。Is typically an object that provides a service to other objects, such as the IMyDependency service.
  • Web サービスを使用する場合はありますが、サービスは Web サービスに関連付けられていません。Is not related to a web service, although the service may use a web service.

フレームワークは、堅牢な ログ システムを備えています。The framework provides a robust logging system. 前の例に示されている IMyDependency の実装は、ログを実装するのではなく、基本的な DI を実演するために記述されています。The IMyDependency implementations shown in the preceding examples were written to demonstrate basic DI, not to implement logging. ほとんどのアプリでは、ロガーを記述する必要はありません。Most apps shouldn't need to write loggers. 次のコードでは、既定のログを使用する方法が示されます。この場合、ConfigureServices にサービスを登録する必要はありません。The following code demonstrates using the default logging, which doesn't require any services to be registered in ConfigureServices:

public class AboutModel : PageModel
{
    private readonly ILogger _logger;

    public AboutModel(ILogger<AboutModel> logger)
    {
        _logger = logger;
    }
    
    public string Message { get; set; }

    public void OnGet()
    {
        Message = $"About page visited at {DateTime.UtcNow.ToLongTimeString()}";
        _logger.LogInformation(Message);
    }
}

前のコードを使用すると、ログ がフレームワークによって提供されるため、ConfigureServices を更新する必要はありません。Using the preceding code, there is no need to update ConfigureServices, because logging is provided by the framework.

Startup に挿入されるサービスServices injected into Startup

サービスは、Startup コンストラクターと Startup.Configure メソッドに挿入できます。Services can be injected into the Startup constructor and the Startup.Configure method.

汎用ホスト (IHostBuilder) を使用すると、次のサービスのみを Startup コンストラクターに挿入できます。Only the following services can be injected into the Startup constructor when using the Generic Host (IHostBuilder):

DI コンテナーに登録されているすべてのサービスを、Startup.Configure メソッドに挿入できます。Any service registered with the DI container can be injected into the Startup.Configure method:

public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
    ...
}

詳細については、「ASP.NET Core でのアプリケーションのスタートアップ」および「起動時の構成へのアクセス」を参照してください。For more information, see ASP.NET Core でのアプリケーションのスタートアップ and Access configuration in Startup.

拡張メソッドを使用したサービスのグループを登録するRegister groups of services with extension methods

ASP.NET Core フレームワークは、関連するサービスのグループを登録するための規則を使用します。The ASP.NET Core framework uses a convention for registering a group of related services. 規則は、単一の Add{GROUP_NAME} 拡張メソッドを使用して、フレームワーク機能に必要なすべてのサービスを登録するというものです。The convention is to use a single Add{GROUP_NAME} extension method to register all of the services required by a framework feature. たとえば、AddControllers 拡張メソッドには、MVC コントローラーに必要なサービスが登録されます。For example, the AddControllers extension method registers the services required for MVC controllers.

次のコードは、個々のユーザー アカウントを使用して Razor ページ テンプレートに基づいて生成されており、拡張メソッド AddDbContext および AddDefaultIdentity を使用してコンテナーにさらにサービスを追加する方法を示しています。The following code is generated by the Razor Pages template using individual user accounts and shows how to add additional services to the container using the extension methods AddDbContext and AddDefaultIdentity:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();
}

サービスを登録し、オプションを構成する次の ConfigureServices メソッドについて考えてみましょう。Consider the following ConfigureServices method, which registers services and configures options:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PositionOptions>(
        Configuration.GetSection(PositionOptions.Position));
    services.Configure<ColorOptions>(
        Configuration.GetSection(ColorOptions.Color));

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddScoped<IMyDependency2, MyDependency2>();

    services.AddRazorPages();
}

関連する登録グループは、サービスを登録するための拡張メソッドに移動できます。Related groups of registrations can be moved to an extension method to register services. たとえば、構成サービスは次のクラスに追加されます。For example, the configuration services are added to the following class:

using ConfigSample.Options;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class MyConfigServiceCollectionExtensions
    {
        public static IServiceCollection AddConfig(
             this IServiceCollection services, IConfiguration config)
        {
            services.Configure<PositionOptions>(
                config.GetSection(PositionOptions.Position));
            services.Configure<ColorOptions>(
                config.GetSection(ColorOptions.Color));

            return services;
        }
    }
}

残りのサービスは、同様のクラスに登録されます。The remaining services are registered in a similar class. 次の ConfigureServices メソッドでは、新しい拡張メソッドを使用してサービスを登録します。The following ConfigureServices method uses the new extension methods to register the services:

public void ConfigureServices(IServiceCollection services)
{
    services.AddConfig(Configuration)
            .AddMyDependencyGroup();

    services.AddRazorPages();
}

注:services.Add{GROUP_NAME} 拡張メソッドは、サービスを追加、場合によっては構成します。Note: Each services.Add{GROUP_NAME} extension method adds and potentially configures services. たとえば、AddControllersWithViews ではビューを持つ MVC コントローラーで必要なサービスが追加され、AddRazorPages では Razor Pages で必要なサービスが追加されます。For example, AddControllersWithViews adds the services MVC controllers with views require, and AddRazorPages adds the services Razor Pages requires. アプリをこの名前付け規則に従わせることをお勧めします。We recommended that apps follow this naming convention. 拡張メソッドを Microsoft.Extensions.DependencyInjection 名前空間に配置して、サービス登録のグループをカプセル化します。Place extension methods in the Microsoft.Extensions.DependencyInjection namespace to encapsulate groups of service registrations.

サービスの有効期間Service lifetimes

.NET での依存関係の挿入」の「サービスの有効期間」を参照してくださいSee Service lifetimes in Dependency injection in .NET

ミドルウェアでスコープ付きサービスを使用するには、次のいずれかの方法を使用します。To use scoped services in middleware, use one of the following approaches:

  • ミドルウェアの Invoke または InvokeAsync メソッドにサービスを挿入します。Inject the service into the middleware's Invoke or InvokeAsync method. コンストラクターの挿入を使用すると、スコープ付きサービスがシングルトンのように動作するように強制されるため、実行時の例外がスローされます。Using constructor injection throws a runtime exception because it forces the scoped service to behave like a singleton. 有効期間と登録のオプション」セクションにあるサンプルは、InvokeAsync による方法を示しています。The sample in the Lifetime and registration options section demonstrates the InvokeAsync approach.
  • ファクトリ ベースのミドルウェアを使用します。Use Factory-based middleware. この方法を使用して登録されたミドルウェアは、クライアント要求 (接続) ごとにアクティブ化されます。これにより、スコープ付きサービスをミドルウェアの InvokeAsync メソッドに挿入できるようになります。Middleware registered using this approach is activated per client request (connection), which allows scoped services to be injected into the middleware's InvokeAsync method.

詳細については、「カスタム ASP.NET Core ミドルウェアを記述する」を参照してください。For more information, see カスタム ASP.NET Core ミドルウェアを記述する.

サービス登録メソッドService registration methods

.NET での依存関係の挿入」の「サービス登録メソッド」を参照してくださいSee Service registration methods in Dependency injection in .NET

テスト用に型のモックを作成する場合に、複数の実装を使用することは一般的です。It's common to use multiple implementations when mocking types for testing.

実装型のみでサービスを登録することは、同じ実装とサービスの型でそのサービスを登録することと同じです。Registering a service with only an implementation type is equivalent to registering that service with the same implementation and service type. 明示的なサービス型を使用しないメソッドを使用してサービスの複数の実装を登録できないのは、このためです。This is why multiple implementations of a service cannot be registered using the methods that don't take an explicit service type. これらのメソッドでは、サービスの複数の "インスタンス" を登録できますが、すべて同じ "実装" 型になります。These methods can register multiple instances of a service, but they will all have the same implementation type.

上記のサービス登録メソッドのずれかを使用して、同じサービス型の複数のサービス インスタンスを登録できます。Any of the above service registration methods can be used to register multiple service instances of the same service type. 次の例では、IMyDependency をサービス型として使用して、AddSingleton を 2 回呼び出します。In the following example, AddSingleton is called twice with IMyDependency as the service type. 2 回目の AddSingleton の呼び出しにより、IMyDependency として解決された場合は前のものがオーバーライドされ、IEnumerable<IMyDependency> を介して複数のサービスが解決された場合は前のものに追加されます。The second call to AddSingleton overrides the previous one when resolved as IMyDependency and adds to the previous one when multiple services are resolved via IEnumerable<IMyDependency>. IEnumerable<{SERVICE}> を介して解決された場合、サービスは登録された順に表示されます。Services appear in the order they were registered when resolved via IEnumerable<{SERVICE}>.

services.AddSingleton<IMyDependency, MyDependency>();
services.AddSingleton<IMyDependency, DifferentDependency>();

public class MyService
{
    public MyService(IMyDependency myDependency, 
       IEnumerable<IMyDependency> myDependencies)
    {
        Trace.Assert(myDependency is DifferentDependency);

        var dependencyArray = myDependencies.ToArray();
        Trace.Assert(dependencyArray[0] is MyDependency);
        Trace.Assert(dependencyArray[1] is DifferentDependency);
    }
}

コンストラクターの挿入の動作Constructor injection behavior

.NET での依存関係の挿入」の「コンストラクターの挿入の動作」を参照してくださいSee Constructor injection behavior in Dependency injection in .NET

Entity Framework コンテキストEntity Framework contexts

既定の Entity Framework コンテキストは、スコープ付き有効期間を使用してサービス コンテナーに追加されます。これは、Web アプリ データベース操作は通常、そのスコープがクライアント要求に設定されるためです。By default, Entity Framework contexts are added to the service container using the scoped lifetime because web app database operations are normally scoped to the client request. 異なる有効期間を使用するには、AddDbContext のオーバーロードを使用して有効期間を指定します。To use a different lifetime, specify the lifetime by using an AddDbContext overload. 有効期間が与えられたサービスの場合、そのサービスより有効期間が短いデータベース コンテキストを使用できません。Services of a given lifetime shouldn't use a database context with a lifetime that's shorter than the service's lifetime.

有効期間と登録のオプションLifetime and registration options

サービスの有効期間とその登録のオプションの違いを示すために、タスクを識別子 OperationId を備えた操作として表す、次のインターフェイスについて考えます。To demonstrate the difference between service lifetimes and their registration options, consider the following interfaces that represent a task as an operation with an identifier, OperationId. 次のインターフェイスに対して操作のサービスの有効期間がどのように構成されているかに応じて、コンテナーからは、クラスによって要求されたときに、サービスの同じインスタンスか別のインスタンスが提供されます。Depending on how the lifetime of an operation's service is configured for the following interfaces, the container provides either the same or different instances of the service when requested by a class:

public interface IOperation
{
    string OperationId { get; }
}

public interface IOperationTransient : IOperation { }
public interface IOperationScoped : IOperation { }
public interface IOperationSingleton : IOperation { }

次の Operation クラスでは、上記のすべてのインターフェイスが実装されます。The following Operation class implements all of the preceding interfaces. Operation コンストラクターによって GUID が生成され、OperationId プロパティの最後の 4 文字が格納されます。The Operation constructor generates a GUID and stores the last 4 characters in the OperationId property:

public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton
{
    public Operation()
    {
        OperationId = Guid.NewGuid().ToString()[^4..];
    }

    public string OperationId { get; }
}

Startup.ConfigureServices メソッドでは、指定された有効期間に従って、Operation クラスの複数の登録が作成されます。The Startup.ConfigureServices method creates multiple registrations of the Operation class according to the named lifetimes:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();

    services.AddRazorPages();
}

サンプル アプリでは、それぞれの要求内、およびそれぞれの要求間におけるオブジェクトの有効期間が示されます。The sample app demonstrates object lifetimes both within and between requests. IndexModel とミドルウェアでは、すべての種類の IOperation 型が要求され、それぞれの OperationId がログに記録されます。The IndexModel and the middleware request each kind of IOperation type and log the OperationId for each:

public class IndexModel : PageModel
{
    private readonly ILogger _logger;
    private readonly IOperationTransient _transientOperation;
    private readonly IOperationSingleton _singletonOperation;
    private readonly IOperationScoped _scopedOperation;

    public IndexModel(ILogger<IndexModel> logger,
                      IOperationTransient transientOperation,
                      IOperationScoped scopedOperation,
                      IOperationSingleton singletonOperation)
    {
        _logger = logger;
        _transientOperation = transientOperation;
        _scopedOperation    = scopedOperation;
        _singletonOperation = singletonOperation;
    }

    public void  OnGet()
    {
        _logger.LogInformation("Transient: " + _transientOperation.OperationId);
        _logger.LogInformation("Scoped: "    + _scopedOperation.OperationId);
        _logger.LogInformation("Singleton: " + _singletonOperation.OperationId);
    }
}

ミドルウェアは IndexModel に類似していて、同じサービスを解決します。Similar to the IndexModel, the middleware resolves the same services:

public class MyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    private readonly IOperationTransient _transientOperation;
    private readonly IOperationSingleton _singletonOperation;

    public MyMiddleware(RequestDelegate next, ILogger<MyMiddleware> logger,
        IOperationTransient transientOperation,
        IOperationSingleton singletonOperation)
    {
        _logger = logger;
        _transientOperation = transientOperation;
        _singletonOperation = singletonOperation;
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context,
        IOperationScoped scopedOperation)
    {
        _logger.LogInformation("Transient: " + _transientOperation.OperationId);
        _logger.LogInformation("Scoped: "    + scopedOperation.OperationId);
        _logger.LogInformation("Singleton: " + _singletonOperation.OperationId);

        await _next(context);
    }
}

public static class MyMiddlewareExtensions
{
    public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyMiddleware>();
    }
}

スコープ付きのサービスは InvokeAsync メソッドで解決する必要があります。Scoped services must be resolved in the InvokeAsync method:

public async Task InvokeAsync(HttpContext context,
    IOperationScoped scopedOperation)
{
    _logger.LogInformation("Transient: " + _transientOperation.OperationId);
    _logger.LogInformation("Scoped: "    + scopedOperation.OperationId);
    _logger.LogInformation("Singleton: " + _singletonOperation.OperationId);

    await _next(context);
}

ロガーの出力は次のようになります。The logger output shows:

  • "一時的な" オブジェクトは常に異なります。Transient objects are always different. 一時的な OperationId 値は、IndexModel とミドルウェアでは異なります。The transient OperationId value is different in the IndexModel and in the middleware.
  • "スコープ付きの" オブジェクトは、それぞれの要求内では同じですが、それぞれの要求間では異なります。Scoped objects are the same for each request but different across each request.
  • "シングルトン" オブジェクトは、すべての要求において同じです。Singleton objects are the same for every request.

ログ出力を減らすには、appsettings.Development.json ファイル内で "Logging:LogLevel:Microsoft:Error" を設定します。To reduce the logging output, set "Logging:LogLevel:Microsoft:Error" in the appsettings.Development.json file:

{
  "MyKey": "MyKey from appsettings.Developement.json",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "System": "Debug",
      "Microsoft": "Error"
    }
  }
}

main からサービスを呼び出すCall services from main

IServiceScopeFactory.CreateScope を使用して IServiceScope を作成し、アプリのスコープ内のスコープ サービスを解決します。Create an IServiceScope with IServiceScopeFactory.CreateScope to resolve a scoped service within the app's scope. この方法は、起動時に初期化タスクを実行するために、スコープ サービスにアクセスするのに便利です。This approach is useful to access a scoped service at startup to run initialization tasks.

次の例は、スコープ付きの IMyDependency サービスにアクセスし、Program.Main でその WriteMessage メソッドを呼び出す方法を示します。The following example shows how to access the scoped IMyDependency service and call its WriteMessage method in Program.Main:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();

        using (var serviceScope = host.Services.CreateScope())
        {
            var services = serviceScope.ServiceProvider;

            try
            {
                var myDependency = services.GetRequiredService<IMyDependency>();
                myDependency.WriteMessage("Call services from main");
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred.");
            }
        }

        host.Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

スコープの検証Scope validation

.NET での依存関係の挿入」の「コンストラクターの挿入の動作」を参照してくださいSee Constructor injection behavior in Dependency injection in .NET

詳しくは、「スコープの検証」をご覧ください。For more information, see Scope validation.

要求サービスRequest Services

ASP.NET Core 要求内で使用可能なサービスは、HttpContext.RequestServices コレクションを通じて公開されます。The services available within an ASP.NET Core request are exposed through the HttpContext.RequestServices collection. 要求内からサービスが要求されると、サービスとその依存関係は RequestServices コレクションから解決されます。When services are requested from inside of a request, the services and their dependencies are resolved from the RequestServices collection.

フレームワークでは要求ごとにスコープが作成され、RequestServices によってスコープ付きサービス プロバイダーが公開されます。The framework creates a scope per request and RequestServices exposes the scoped service provider. すべてのスコープ サービスは、要求がアクティブである限り有効です。All scoped services are valid for as long as the request is active.

注意

RequestServices コレクションからサービスを解決するよりも、コンストラクターのパラメーターとして依存関係を要求するようにします。Prefer requesting dependencies as constructor parameters to resolving services from the RequestServices collection. これにより、テストしやすいクラスが生成されます。This results in classes that are easier to test.

依存関係の挿入のためのサービスの設計Design services for dependency injection

依存関係の挿入のためのサービスの設計時には:When designing services for dependency injection:

  • ステートフル、静的クラス、およびメンバーは避けてください。Avoid stateful, static classes and members. 代わりにシングルトン サービスを使用するようにアプリを設計し、グローバルな状態を作成しないようにします。Avoid creating global state by designing apps to use singleton services instead.
  • サービス内部で依存関係のあるクラスを直接インスタンス化することを回避します。Avoid direct instantiation of dependent classes within services. 直接のインスタンス化は、コードの固有の実装につながります。Direct instantiation couples the code to a particular implementation.
  • サービスを、小さく、十分に要素に分割された、テストしやすいものにします。Make services small, well-factored, and easily tested.

クラスに含まれる挿入される依存関係が多すぎる場合、それは、クラスの責任が多すぎて、単一責任の原則 (SRP) に違反しているサインである可能性があります。If a class has a lot of injected dependencies, it might be a sign that the class has too many responsibilities and violates the Single Responsibility Principle (SRP). 責任の一部を新しいクラスに移動することにより、クラスのリファクタリングを試みます。Attempt to refactor the class by moving some of its responsibilities into new classes. Razor Pages のページ モデル クラスと MVC コントローラー クラスは、UI の問題に集中する必要があることに留意します。Keep in mind that Razor Pages page model classes and MVC controller classes should focus on UI concerns.

サービスの破棄Disposal of services

コンテナーは、作成する IDisposable 型の Dispose を呼び出します。The container calls Dispose for the IDisposable types it creates. コンテナーから解決されたサービスが、開発者によって破棄されることはありません。Services resolved from the container should never be disposed by the developer. 型またはファクトリがシングルトンとして登録されている場合、コンテナーによってシングルトンが自動的に破棄されます。If a type or factory is registered as a singleton, the container disposes the singleton automatically.

次の例では、サービスがサービス コンテナーによって作成され、自動的に破棄されます。In the following example, the services are created by the service container and disposed automatically:

public class Service1 : IDisposable
{
    private bool _disposed;

    public void Write(string message)
    {
        Console.WriteLine($"Service1: {message}");
    }

    public void Dispose()
    {
        if (_disposed)
            return;

        Console.WriteLine("Service1.Dispose");
        _disposed = true;
    }
}

public class Service2 : IDisposable
{
    private bool _disposed;

    public void Write(string message)
    {
        Console.WriteLine($"Service2: {message}");
    }

    public void Dispose()
    {
        if (_disposed)
            return;

        Console.WriteLine("Service2.Dispose");
        _disposed = true;
    }
}

public interface IService3
{
    public void Write(string message);
}

public class Service3 : IService3, IDisposable
{
    private bool _disposed;

    public Service3(string myKey)
    {
        MyKey = myKey;
    }

    public string MyKey { get; }

    public void Write(string message)
    {
        Console.WriteLine($"Service3: {message}, MyKey = {MyKey}");
    }

    public void Dispose()
    {
        if (_disposed)
            return;

        Console.WriteLine("Service3.Dispose");
        _disposed = true;
    }
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<Service1>();
    services.AddSingleton<Service2>();
    
    var myKey = Configuration["MyKey"];
    services.AddSingleton<IService3>(sp => new Service3(myKey));

    services.AddRazorPages();
}
public class IndexModel : PageModel
{
    private readonly Service1 _service1;
    private readonly Service2 _service2;
    private readonly IService3 _service3;

    public IndexModel(Service1 service1, Service2 service2, IService3 service3)
    {
        _service1 = service1;
        _service2 = service2;
        _service3 = service3;
    }

    public void OnGet()
    {
        _service1.Write("IndexModel.OnGet");
        _service2.Write("IndexModel.OnGet");
        _service3.Write("IndexModel.OnGet");
    }
}

デバッグ コンソールでは、インデックス ページを更新するたびに次の出力が表示されます。The debug console shows the following output after each refresh of the Index page:

Service1: IndexModel.OnGet
Service2: IndexModel.OnGet
Service3: IndexModel.OnGet
Service1.Dispose

サービス コンテナーによって作成されていないサービスServices not created by the service container

次のコードがあるとします。Consider the following code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(new Service1());
    services.AddSingleton(new Service2());

    services.AddRazorPages();
}

上のコードでは以下の操作が行われます。In the preceding code:

  • サービス インスタンスは、サービス コンテナーによって作成されるわけではありません。The service instances aren't created by the service container.
  • フレームワークでは、サービスが自動的に破棄されることはありません。The framework doesn't dispose of the services automatically.
  • サービスを破棄する責任は開発者にあります。The developer is responsible for disposing the services.

一時的なインスタンスと共有インスタンスのための IDisposable ガイダンスIDisposable guidance for Transient and shared instances

.NET での依存関係の挿入」の「一時的なインスタンスと共有インスタンスのための IDisposable ガイダンス」を参照してくださいSee IDisposable guidance for Transient and shared instance in Dependency injection in .NET

既定のサービス コンテナーの置換Default service container replacement

.NET での依存関係の挿入」の「既定のサービス コンテナーの置換」を参照してくださいSee Default service container replacement in Dependency injection in .NET

RecommendationsRecommendations

.NET での依存関係の挿入」の「推奨事項」を参照してくださいSee Recommendations in Dependency injection in .NET

  • サービス ロケーター パターン の使用は避けてください。Avoid using the service locator pattern. たとえば、サービス インスタンスを取得する場合、DI を使用できるときに、GetService を呼び出さないでください。For example, don't invoke GetService to obtain a service instance when you can use DI instead:

    正しくない:Incorrect:

    正しくないコード

    正しい:Correct:

    public class MyClass
    {
        private readonly IOptionsMonitor<MyOptions> _optionsMonitor;
    
        public MyClass(IOptionsMonitor<MyOptions> optionsMonitor)
        {
            _optionsMonitor = optionsMonitor;
        }
    
        public void MyMethod()
        {
            var option = _optionsMonitor.CurrentValue.Option;
    
            ...
        }
    }
    
  • 回避すべき別のサービス ロケーターのバリエーションは、実行時に依存関係を解決するファクトリを挿入することです。Another service locator variation to avoid is injecting a factory that resolves dependencies at runtime. この両方のプラクティスによって、複数の制御の反転方式が組み合わせられます。Both of these practices mix Inversion of Control strategies.

  • HttpContext への静的なアクセスを回避します (たとえば IHttpContextAccessor.HttpContext)。Avoid static access to HttpContext (for example, IHttpContextAccessor.HttpContext).

  • ConfigureServicesBuildServiceProvider を呼び出すことは避けてください。Avoid calls to BuildServiceProvider in ConfigureServices. BuildServiceProvider の呼び出しは、通常、開発者が ConfigureServices でサービスを解決する必要がある場合に発生します。Calling BuildServiceProvider typically happens when the developer wants to resolve a service in ConfigureServices. たとえば、構成から LoginPath が読み込まれる場合を考えてみます。For example, consider the case where the LoginPath is loaded from configuration. 次の方法は避けてください。Avoid the following approach:

    BuildServiceProvider を呼び出すコードが正しくありません

    上の図では、services.BuildServiceProvider の下の緑の波線を選択すると、次の ASP0000 警告が表示されます。In the preceding image, selecting the green wavy line under services.BuildServiceProvider shows the following ASP0000 warning:

    アプリケーション コードから ASP0000 呼び出し 'BuildServiceProvider' を行うと、シングルトン サービスの追加のコピーが作成されます。ASP0000 Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. 'Configure' のパラメーターとして依存関係挿入サービスなどの代替手段を検討してください。Consider alternatives such as dependency injecting services as parameters to 'Configure'.

    BuildServiceProvider を呼び出すと、2 つ目のコンテナーが作成されます。これを使用すれば、破損したシングルトンが作成され、複数のコンテナーにまたがるオブジェクト グラフへの参照を生じさせることができます。Calling BuildServiceProvider creates a second container, which can create torn singletons and cause references to object graphs across multiple containers.

    LoginPath を取得する正しい方法は、DI のオプション パターンの組み込みサポートを使用することです。A correct way to get LoginPath is to use the options pattern's built-in support for DI:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie();
    
        services.AddOptions<CookieAuthenticationOptions>(
                            CookieAuthenticationDefaults.AuthenticationScheme)
            .Configure<IMyService>((options, myService) =>
            {
                options.LoginPath = myService.GetLoginPath();
            });
    
        services.AddRazorPages();
    }
    
  • 破棄可能な一時的なサービスは、破棄のためにコンテナーによってキャプチャされます。Disposable transient services are captured by the container for disposal. これにより、最上位のコンテナーから解決された場合、メモリ リークが発生する可能性があります。This can turn into a memory leak if resolved from the top level container.

  • スコープの検証を有効にすることで、アプリにスコープ付きサービスをキャプチャするシングルトンがないようにします。Enable scope validation to make sure the app doesn't have singletons that capture scoped services. 詳しくは、「スコープの検証」をご覧ください。For more information, see Scope validation.

どのような推奨事項であっても、それを無視する必要がある状況が発生する可能性があります。Like all sets of recommendations, you may encounter situations where ignoring a recommendation is required. 例外はまれです。ほとんどがフレームワーク自体の内の特殊なケースです。Exceptions are rare, mostly special cases within the framework itself.

DI は静的/グローバル オブジェクト アクセス パターンの 代替機能 です。DI is an alternative to static/global object access patterns. 静的オブジェクト アクセスと併用した場合、DI のメリットを実現することはできません。You may not be able to realize the benefits of DI if you mix it with static object access.

Orchard Core は、ASP.NET Core でモジュール型のマルチテナント アプリケーションを構築するためのアプリケーション フレームワークです。Orchard Core is an application framework for building modular, multi-tenant applications on ASP.NET Core. 詳細については、Orchard Core のドキュメントを参照してください。For more information, see the Orchard Core Documentation.

CMS 固有の機能を使用せずに Orchard Core Framework のみを使用してモジュール型のマルチテナント アプリを構築する方法の例については、Orchard Core のサンプルを参照してください。See the Orchard Core samples for examples of how to build modular and multi-tenant apps using just the Orchard Core Framework without any of its CMS-specific features.

フレームワークが提供するサービスFramework-provided services

Startup.ConfigureServices メソッドでは、Entity Framework Core や ASP.NET Core MVC のようなプラットフォーム機能など、アプリが使うサービスが登録されます。The Startup.ConfigureServices method registers services that the app uses, including platform features, such as Entity Framework Core and ASP.NET Core MVC. 最初に、ConfigureServices に提供される IServiceCollection には、フレームワークによって定義されたサービスがあります (ホストの構成方法によって異なります)。Initially, the IServiceCollection provided to ConfigureServices has services defined by the framework depending on how the host was configured. ASP.NET Core テンプレートに基づくアプリでは、フレームワークによって 250 を超えるサービスが登録されます。For apps based on the ASP.NET Core templates, the framework registers more than 250 services.

次の表に、フレームワークによって登録されるサービスのごく一部を示します。The following table lists a small sample of these framework-registered services:

サービスの種類Service Type 有効期間Lifetime
Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory 一時的Transient
IHostApplicationLifetime シングルトンSingleton
IWebHostEnvironment シングルトンSingleton
Microsoft.AspNetCore.Hosting.IStartup シングルトンSingleton
Microsoft.AspNetCore.Hosting.IStartupFilter 一時的Transient
Microsoft.AspNetCore.Hosting.Server.IServer シングルトンSingleton
Microsoft.AspNetCore.Http.IHttpContextFactory 一時的Transient
Microsoft.Extensions.Logging.ILogger<TCategoryName> シングルトンSingleton
Microsoft.Extensions.Logging.ILoggerFactory シングルトンSingleton
Microsoft.Extensions.ObjectPool.ObjectPoolProvider シングルトンSingleton
Microsoft.Extensions.Options.IConfigureOptions<TOptions> 一時的Transient
Microsoft.Extensions.Options.IOptions<TOptions> シングルトンSingleton
System.Diagnostics.DiagnosticSource シングルトンSingleton
System.Diagnostics.DiagnosticListener シングルトンSingleton

その他の技術情報Additional resources

作成者: Steve SmithScott AddieBrandon DahlerBy Steve Smith, Scott Addie, and Brandon Dahler

ASP.NET Core では依存関係の挿入 (DI) ソフトウェア設計パターンがサポートされています。これは、クラスとその依存関係の間で制御の反転 (IoC) を実現するための手法です。ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.

MVC コントローラー内部における依存関係の挿入に固有の情報については、ASP.NET Core でのコントローラーへの依存関係の挿入 をご覧ください。For more information specific to dependency injection within MVC controllers, see ASP.NET Core でのコントローラーへの依存関係の挿入.

サンプル コードを表示またはダウンロードします (ダウンロード方法)。View or download sample code (how to download)

依存関係の挿入の概要Overview of dependency injection

"依存関係" とは、他のオブジェクトが必要とする任意のオブジェクトのことです。A dependency is any object that another object requires. アプリ内の他のクラスが依存している、次の WriteMessage メソッドを備えた MyDependency クラスを調べます。Examine the following MyDependency class with a WriteMessage method that other classes in an app depend upon:

public class MyDependency
{
    public MyDependency()
    {
    }

    public Task WriteMessage(string message)
    {
        Console.WriteLine(
            $"MyDependency.WriteMessage called. Message: {message}");

        return Task.FromResult(0);
    }
}

クラスで WriteMessage メソッドを使用できるようにするために、MyDependency クラスのインスタンスを作成することができます。An instance of the MyDependency class can be created to make the WriteMessage method available to a class. MyDependency クラスは IndexModel クラスの依存関係です。The MyDependency class is a dependency of the IndexModel class:

public class IndexModel : PageModel
{
    MyDependency _dependency = new MyDependency();

    public async Task OnGetAsync()
    {
        await _dependency.WriteMessage(
            "IndexModel.OnGetAsync created this message.");
    }
}

このクラスは MyDependency のインスタンスを作成し、これに直接依存しています。The class creates and directly depends on the MyDependency instance. コードの依存関係 (前の例など) には問題が含まれ、次の理由から回避する必要があります。Code dependencies (such as the previous example) are problematic and should be avoided for the following reasons:

  • MyDependency を別の実装で置き換えるには、クラスを変更する必要があります。To replace MyDependency with a different implementation, the class must be modified.
  • MyDependency が依存関係を含んでいる場合、これらはクラスによって構成する必要があります。If MyDependency has dependencies, they must be configured by the class. 複数のクラスが MyDependency に依存している大規模なプロジェクトでは、構成コードがアプリ全体に分散するようになります。In a large project with multiple classes depending on MyDependency, the configuration code becomes scattered across the app.
  • このような実装では、単体テストを行うことが困難です。This implementation is difficult to unit test. アプリはモックまたはスタブの MyDependency クラスを使用する必要がありますが、この方法では不可能です。The app should use a mock or stub MyDependency class, which isn't possible with this approach.

依存関係の挿入は、次の方法によってこれらの問題に対応します。Dependency injection addresses these problems through:

  • 依存関係の実装を抽象化するための、インターフェイスまたは基底クラスの使用。The use of an interface or base class to abstract the dependency implementation.
  • サービス コンテナー内の依存関係の登録。Registration of the dependency in a service container. ASP.NET Core には、組み込みのサービス コンテナー IServiceProvider が用意されています。ASP.NET Core provides a built-in service container, IServiceProvider. サービスはアプリの Startup.ConfigureServices メソッドに登録されています。Services are registered in the app's Startup.ConfigureServices method.
  • サービスを使用するクラスのコンストラクターへの、サービスの "挿入"。Injection of the service into the constructor of the class where it's used. 依存関係のインスタンスの作成、およびインスタンスが不要になったときの廃棄の役割を、フレームワークが担当します。The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed.

サンプル アプリでは、サービスがアプリに提供するメソッドが IMyDependency インターフェイスによって定義されます。In the sample app, the IMyDependency interface defines a method that the service provides to the app:

public interface IMyDependency
{
    Task WriteMessage(string message);
}

このインターフェイスは、具象型 MyDependency によって実装されます。This interface is implemented by a concrete type, MyDependency:

public class MyDependency : IMyDependency
{
    private readonly ILogger<MyDependency> _logger;

    public MyDependency(ILogger<MyDependency> logger)
    {
        _logger = logger;
    }

    public Task WriteMessage(string message)
    {
        _logger.LogInformation(
            "MyDependency.WriteMessage called. Message: {Message}", 
            message);

        return Task.FromResult(0);
    }
}

MyDependency では、コンストラクター内で ILogger<TCategoryName> が要求されます。MyDependency requests an ILogger<TCategoryName> in its constructor. 依存関係の挿入をチェーン形式で使用することはよくあります。It's not unusual to use dependency injection in a chained fashion. 次に、要求されたそれぞれの依存関係が、それ自身の依存関係を要求します。Each requested dependency in turn requests its own dependencies. コンテナーによってグラフ内の依存関係が解決され、完全に解決されたサービスが返されます。The container resolves the dependencies in the graph and returns the fully resolved service. 解決する必要がある依存関係の集合的なセットは、通常、"依存関係ツリー"、"依存関係グラフ"、または "オブジェクト グラフ" と呼ばれます。The collective set of dependencies that must be resolved is typically referred to as a dependency tree, dependency graph, or object graph.

IMyDependencyILogger<TCategoryName> をサービス コンテナーに登録する必要があります。IMyDependency and ILogger<TCategoryName> must be registered in the service container. IMyDependencyStartup.ConfigureServices に登録されます。IMyDependency is registered in Startup.ConfigureServices. ILogger<TCategoryName> はログ記録の抽象化インフラストラクチャによって登録されます。したがって、これは、フレームワークによって既定で登録されるフレームワークが提供するサービスです。ILogger<TCategoryName> is registered by the logging abstractions infrastructure, so it's a framework-provided service registered by default by the framework.

コンテナーでは、(ジェネリック) オープン型を活用し、すべての (ジェネリック) 構築型を登録する必要をなくすことで、ILogger<TCategoryName> を解決します。The container resolves ILogger<TCategoryName> by taking advantage of (generic) open types, eliminating the need to register every (generic) constructed type:

services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));

サンプル アプリにおいて、IMyDependency サービスは MyDependency 具象型を使用して登録されます。In the sample app, the IMyDependency service is registered with the concrete type MyDependency. 登録によって、サービスの有効期間が 1 つの要求の有効期間に範囲設定されます。The registration scopes the service lifetime to the lifetime of a single request. サービスの有効期間については、このトピックの後半で説明します。Service lifetimes are described later in this topic.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));

    // OperationService depends on each of the other Operation types.
    services.AddTransient<OperationService, OperationService>();
}

注意

services.Add{SERVICE_NAME} 拡張メソッドによって、サービスが追加、場合によっては構成されます。Each services.Add{SERVICE_NAME} extension method adds, and potentially configures, services. たとえば、services.AddControllersWithViewsservices.AddRazorPagesservices.AddControllers を使用すると、ASP.NET Core アプリに必要なサービスが追加されます。For example, services.AddControllersWithViews, services.AddRazorPages, and services.AddControllers adds the services ASP.NET Core apps require. アプリをこの規則に従わせることをお勧めします。We recommended that apps follow this convention. 拡張メソッドを Microsoft.Extensions.DependencyInjection 名前空間に配置して、サービス登録のグループをカプセル化します。Place extension methods in the Microsoft.Extensions.DependencyInjection namespace to encapsulate groups of service registrations. DI 拡張メソッド用の名前空間部分として Microsoft.Extensions.DependencyInjection を含めると、次のようになります。Including the namespace portion Microsoft.Extensions.DependencyInjection for DI extension methods also:

  • using ブロックを追加しなくても、それらを IntelliSense で表示することができます。Allows them to be displayed in IntelliSense without adding additional using blocks.
  • それらの拡張メソッドの通常の呼び出し元である Startup クラス内で using ステートメントが過剰になることはありません。Prevents excessive using statements in the Startup class where these extension methods are typically called from.

サービスのコンストラクターでビルトイン型 (string など) が必要な場合は、構成オプション パターンを使って型を挿入することができます。If the service's constructor requires a built in type, such as a string, the type can be injected by using configuration or the options pattern:

public class MyDependency : IMyDependency
{
    public MyDependency(IConfiguration config)
    {
        var myStringValue = config["MyStringKey"];

        // Use myStringValue
    }

    ...
}

クラスのコンストラクター経由でサービスのインスタンスが要求されます。サービスはプライベート フィールドに割り当てられて使用されます。An instance of the service is requested via the constructor of a class where the service is used and assigned to a private field. このフィールドは、クラス全体で必要に応じてサービスにアクセスするために使用されます。The field is used to access the service as necessary throughout the class.

サンプル アプリでは、IMyDependency インスタンスが要求され、サービスの WriteMessage メソッドを呼び出すために使用されます。In the sample app, the IMyDependency instance is requested and used to call the service's WriteMessage method:

public class IndexModel : PageModel
{
    private readonly IMyDependency _myDependency;

    public IndexModel(
        IMyDependency myDependency, 
        OperationService operationService,
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance singletonInstanceOperation)
    {
        _myDependency = myDependency;
        OperationService = operationService;
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = singletonInstanceOperation;
    }

    public OperationService OperationService { get; }
    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }

    public async Task OnGetAsync()
    {
        await _myDependency.WriteMessage(
            "IndexModel.OnGetAsync created this message.");
    }
}

Startup に挿入されるサービスServices injected into Startup

汎用ホスト (IHostBuilder) を使用すると、次のサービスの種類のみを Startup コンストラクターに挿入できます。Only the following service types can be injected into the Startup constructor when using the Generic Host (IHostBuilder):

サービスは Startup.Configure に挿入できます。Services can be injected into Startup.Configure:

public void Configure(IApplicationBuilder app, IOptions<MyOptions> options)
{
    ...
}

詳細については、「ASP.NET Core でのアプリケーションのスタートアップ」を参照してください。For more information, see ASP.NET Core でのアプリケーションのスタートアップ.

フレームワークが提供するサービスFramework-provided services

Startup.ConfigureServices メソッドでは、Entity Framework Core や ASP.NET Core MVC のようなプラットフォーム機能など、アプリが使うサービスを定義する必要があります。The Startup.ConfigureServices method is responsible for defining the services that the app uses, including platform features, such as Entity Framework Core and ASP.NET Core MVC. 最初に、ConfigureServices に提供される IServiceCollection には、フレームワークによって定義されたサービスがあります (ホストの構成方法によって異なります)。Initially, the IServiceCollection provided to ConfigureServices has services defined by the framework depending on how the host was configured. ASP.NET Core テンプレートに基づくアプリが、フレームワークによって登録された何百ものサービスを持つことも珍しくありません。It's not uncommon for an app based on an ASP.NET Core template to have hundreds of services registered by the framework. 次の表に、フレームワークによって登録されたサービスのごく一部のサンプルを示します。A small sample of framework-registered services is listed in the following table.

サービスの種類Service Type 有効期間Lifetime
Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory 一時的Transient
Microsoft.AspNetCore.Hosting.IApplicationLifetime シングルトンSingleton
Microsoft.AspNetCore.Hosting.IHostingEnvironment シングルトンSingleton
Microsoft.AspNetCore.Hosting.IStartup シングルトンSingleton
Microsoft.AspNetCore.Hosting.IStartupFilter 一時的Transient
Microsoft.AspNetCore.Hosting.Server.IServer シングルトンSingleton
Microsoft.AspNetCore.Http.IHttpContextFactory 一時的Transient
Microsoft.Extensions.Logging.ILogger<TCategoryName> シングルトンSingleton
Microsoft.Extensions.Logging.ILoggerFactory シングルトンSingleton
Microsoft.Extensions.ObjectPool.ObjectPoolProvider シングルトンSingleton
Microsoft.Extensions.Options.IConfigureOptions<TOptions> 一時的Transient
Microsoft.Extensions.Options.IOptions<TOptions> シングルトンSingleton
System.Diagnostics.DiagnosticSource シングルトンSingleton
System.Diagnostics.DiagnosticListener シングルトンSingleton

拡張メソッドを使用した追加サービスの登録するRegister additional services with extension methods

サービス (および必要であればサービスが依存するサービス) を登録するためにサービス コレクションの拡張メソッドを使用できる場合は、1 つの Add{SERVICE_NAME} 拡張メソッドを使用してそのサービスが必要とするすべてのサービスを登録することが規則です。When a service collection extension method is available to register a service (and its dependent services, if required), the convention is to use a single Add{SERVICE_NAME} extension method to register all of the services required by that service. 次のコードは、拡張メソッド AddDbContext<TContext>AddIdentityCore を使用して、コンテナーに追加のサービスを追加する方法の例です。The following code is an example of how to add additional services to the container using the extension methods AddDbContext<TContext> and AddIdentityCore:

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    ...
}

詳細については、API ドキュメントにある ServiceCollection クラスを参照してください。For more information, see the ServiceCollection class in the API documentation.

サービスの有効期間Service lifetimes

登録される各サービスの適切な有効期間を選択します。Choose an appropriate lifetime for each registered service. ASP.NET Core サービスは、次の有効期間で構成できます。ASP.NET Core services can be configured with the following lifetimes:

一時的Transient

有効期間が一時的なサービス (AddTransient) は、サービス コンテナーから要求されるたびに作成されます。Transient lifetime services (AddTransient) are created each time they're requested from the service container. この有効期間は、軽量でステートレスのサービスに最適です。This lifetime works best for lightweight, stateless services.

要求を処理するアプリでは、一時的なサービスが要求の最後に破棄されます。In apps that process requests, transient services are disposed at the end of the request.

スコープScoped

有効期間がスコープのサービス (AddScoped) は、クライアント要求 (接続) ごとに 1 回作成されます。Scoped lifetime services (AddScoped) are created once per client request (connection).

要求を処理するアプリでは、スコープ付きサービスは要求の最後で破棄されます。In apps that process requests, scoped services are disposed at the end of the request.

警告

ミドルウェアでスコープ サービスを使用している場合、サービスを Invoke または InvokeAsync メソッドに追加します。When using a scoped service in a middleware, inject the service into the Invoke or InvokeAsync method. コンストラクターを使用して挿入すると、サービスがシングルトンのように動作するよう強制されるので、コンストラクターの挿入を使用した挿入は行わないでください。Don't inject via constructor injection because it forces the service to behave like a singleton. 詳細については、「カスタム ASP.NET Core ミドルウェアを記述する」を参照してください。For more information, see カスタム ASP.NET Core ミドルウェアを記述する.

シングルトンSingleton

有効期間がシングルトンのサービス (AddSingleton) は、最初に要求されたときに作成されます (または、Startup.ConfigureServices が実行されて、サービス登録でインスタンスが指定された場合)。Singleton lifetime services (AddSingleton) are created the first time they're requested (or when Startup.ConfigureServices is run and an instance is specified with the service registration). 以降の要求は、すべて同じインスタンスを使用します。Every subsequent request uses the same instance. アプリをシングルトンで動作させる必要がある場合は、サービス コンテナーによるサービスの有効期間の管理を許可することをお勧めします。If the app requires singleton behavior, allowing the service container to manage the service's lifetime is recommended. クラス内のオブジェクトの有効期間を管理するために、シングルトンの設計パターンを実装してユーザー コードを提供しないでください。Don't implement the singleton design pattern and provide user code to manage the object's lifetime in the class.

要求を処理するアプリでは、ServiceProvider がアプリのシャットダウン時に破棄されたとき、シングルトン サービスが破棄されます。In apps that process requests, singleton services are disposed when the ServiceProvider is disposed at app shutdown.

警告

シングルトンからスコープ サービスを解決するのは危険です。It's dangerous to resolve a scoped service from a singleton. 後続の要求を処理する際に、サービスが正しくない状態になる可能性があります。It may cause the service to have incorrect state when processing subsequent requests.

サービス登録メソッドService registration methods

サービス登録拡張メソッドでは、特定のシナリオで役立つオーバーロードが提供されます。Service registration extension methods offer overloads that are useful in specific scenarios.

メソッドMethod 自動Automatic
objectobject
破棄disposal
複数Multiple
実装implementations
引数を渡すPass args
Add{LIFETIME}<{SERVICE}, {IMPLEMENTATION}>()
例:Example:
services.AddSingleton<IMyDep, MyDep>();
はいYes はいYes いいえNo
Add{LIFETIME}<{SERVICE}>(sp => new {IMPLEMENTATION})
次に例を示します。Examples:
services.AddSingleton<IMyDep>(sp => new MyDep());
services.AddSingleton<IMyDep>(sp => new MyDep("A string!"));
はいYes はいYes はいYes
Add{LIFETIME}<{IMPLEMENTATION}>()
例:Example:
services.AddSingleton<MyDep>();
はいYes いいえNo いいえNo
AddSingleton<{SERVICE}>(new {IMPLEMENTATION})
次に例を示します。Examples:
services.AddSingleton<IMyDep>(new MyDep());
services.AddSingleton<IMyDep>(new MyDep("A string!"));
いいえNo はいYes はいYes
AddSingleton(new {IMPLEMENTATION})
次に例を示します。Examples:
services.AddSingleton(new MyDep());
services.AddSingleton(new MyDep("A string!"));
いいえNo いいえNo はいYes

型の廃棄の詳細については、「サービスの破棄」を参照してください。For more information on type disposal, see the Disposal of services section. 実装が複数の場合の一般的なシナリオとしては、テスト用に型のモックを作成します。A common scenario for multiple implementations is mocking types for testing.

実装型のみでサービスを登録することは、同じ実装とサービスの型でそのサービスを登録することと同じです。Registering a service with only an implementation type is equivalent to registering that service with the same implementation and service type. 明示的なサービス型を使用しないメソッドを使用してサービスの複数の実装を登録できないのは、このためです。This is why multiple implementations of a service cannot be registered using the methods that don't take an explicit service type. これらのメソッドでは、サービスの複数の "インスタンス" を登録できますが、すべて同じ "実装" 型になります。These methods can register multiple instances of a service, but they will all have the same implementation type.

上記のサービス登録メソッドのずれかを使用して、同じサービス型の複数のサービス インスタンスを登録できます。Any of the above service registration methods can be used to register multiple service instances of the same service type. 次の例では、IMyDependency をサービス型として使用して、AddSingleton を 2 回呼び出します。In the following example, AddSingleton is called twice with IMyDependency as the service type. 2 回目の AddSingleton の呼び出しにより、IMyDependency として解決された場合は前のものがオーバーライドされ、IEnumerable<IMyDependency> を介して複数のサービスが解決された場合は前のものに追加されます。The second call to AddSingleton overrides the previous one when resolved as IMyDependency and adds to the previous one when multiple services are resolved via IEnumerable<IMyDependency>. IEnumerable<{SERVICE}> を介して解決された場合、サービスは登録された順に表示されます。Services appear in the order they were registered when resolved via IEnumerable<{SERVICE}>.

services.AddSingleton<IMyDependency, MyDependency>();
services.AddSingleton<IMyDependency, DifferentDependency>();

public class MyService
{
    public MyService(IMyDependency myDependency, 
       IEnumerable<IMyDependency> myDependencies)
    {
        Trace.Assert(myDependency is DifferentDependency);

        var dependencyArray = myDependencies.ToArray();
        Trace.Assert(dependencyArray[0] is MyDependency);
        Trace.Assert(dependencyArray[1] is DifferentDependency);
    }
}

フレームワークには TryAdd{LIFETIME} 拡張メソッドも用意されており、実装がまだ登録されていない場合にのみ、サービスが登録されます。The framework also provides TryAdd{LIFETIME} extension methods, which register the service only if there isn't already an implementation registered.

次の例では、AddSingleton の呼び出しによって、IMyDependency の実装として MyDependency が登録されます。In the following example, the call to AddSingleton registers MyDependency as an implementation for IMyDependency. IMyDependency には登録された実装が既に含まれているため、TryAddSingleton の呼び出しでは何も行われません。The call to TryAddSingleton has no effect because IMyDependency already has a registered implementation.

services.AddSingleton<IMyDependency, MyDependency>();
// The following line has no effect:
services.TryAddSingleton<IMyDependency, DifferentDependency>();

public class MyService
{
    public MyService(IMyDependency myDependency, 
        IEnumerable<IMyDependency> myDependencies)
    {
        Trace.Assert(myDependency is MyDependency);
        Trace.Assert(myDependencies.Single() is MyDependency);
    }
}

詳細については次を参照してください:For more information, see:

TryAddEnumerable(ServiceDescriptor) メソッドでは、"同じ型" の実装がまだ存在しない場合にのみサービスが登録されます。TryAddEnumerable(ServiceDescriptor) methods only register the service if there isn't already an implementation of the same type. 複数のサービスは、IEnumerable<{SERVICE}> によって解決されます。Multiple services are resolved via IEnumerable<{SERVICE}>. サービスを登録するとき、開発者は同じ型のものがまだ追加されていない場合にのみインスタンスを追加します。When registering services, the developer only wants to add an instance if one of the same type hasn't already been added. 一般に、このメソッドは、インスタンスのコピーが 2 つコンテナーに登録されるのを回避するために、ライブラリ作成者によって使用されます。Generally, this method is used by library authors to avoid registering two copies of an instance in the container.

次の例の最初の行では、IMyDep1MyDep を登録します。In the following example, the first line registers MyDep for IMyDep1. 2 行目では IMyDep2MyDep を登録します。The second line registers MyDep for IMyDep2. 3 行目では何も行われません。IMyDep1 には MyDep の登録済みの実装が既に含まれているからです。The third line has no effect because IMyDep1 already has a registered implementation of MyDep:

public interface IMyDep1 {}
public interface IMyDep2 {}

public class MyDep : IMyDep1, IMyDep2 {}

services.TryAddEnumerable(ServiceDescriptor.Singleton<IMyDep1, MyDep>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMyDep2, MyDep>());
// Two registrations of MyDep for IMyDep1 is avoided by the following line:
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMyDep1, MyDep>());

コンストラクターの挿入の動作Constructor injection behavior

サービスは 2 つのメカニズムによって解決できます。Services can be resolved by two mechanisms:

  • IServiceProvider
  • ActivatorUtilities:依存関係の挿入コンテナーにサービスを登録することなくオブジェクトの作成を許可します。ActivatorUtilities: Permits object creation without service registration in the dependency injection container. ActivatorUtilities はユーザー側の抽象化 (タグ ヘルパー、MVC コントローラー、モデル バインダーなど) で使用されます。ActivatorUtilities is used with user-facing abstractions, such as Tag Helpers, MVC controllers, and model binders.

コンストラクターは、依存関係の挿入によって提供されない引数を受け取ることができますが、引数は既定値を割り当てる必要があります。Constructors can accept arguments that aren't provided by dependency injection, but the arguments must assign default values.

IServiceProvider または ActivatorUtilities によってサービスを解決する場合、コンストラクターの挿入には、"パブリック" コンストラクターが必要です。When services are resolved by IServiceProvider or ActivatorUtilities, constructor injection requires a public constructor.

ActivatorUtilities によってサービスを解決する場合、コンストラクターの挿入には、該当するコンストラクターが 1 つだけ存在することが必要です。When services are resolved by ActivatorUtilities, constructor injection requires that only one applicable constructor exists. コンストラクターのオーバーロードはサポートされていますが、依存関係の挿入によってすべての引数を設定できるオーバーロードは 1 つしか存在できません。Constructor overloads are supported, but only one overload can exist whose arguments can all be fulfilled by dependency injection.

Entity Framework コンテキストEntity Framework contexts

Entity Framework コンテキストでは通常、範囲が指定された有効期間が利用され、サービス コンテナーに追加されます。これは、Web アプリ データベース操作は通常、その範囲がクライアント要求に設定されるためです。Entity Framework contexts are usually added to the service container using the scoped lifetime because web app database operations are normally scoped to the client request. データベース コンテキストの登録時、AddDbContext<TContext> オーバーロードによって有効期間が指定されなかった場合、既定の有効期間が範囲となります。The default lifetime is scoped if a lifetime isn't specified by an AddDbContext<TContext> overload when registering the database context. 有効期間が与えられたサービスの場合、サービスより有効期間が短いデータベース コンテキストを使用できません。Services of a given lifetime shouldn't use a database context with a shorter lifetime than the service.

有効期間と登録のオプションLifetime and registration options

有効期間と登録のオプションの違いを示すために、タスクを一意の識別子 OperationId を備えた操作として表す、次のインターフェイスについて考えます。To demonstrate the difference between the lifetime and registration options, consider the following interfaces that represent tasks as an operation with a unique identifier, OperationId. 次のインターフェイスに対して操作のサービスの有効期間がどのように構成されているかに応じて、コンテナーは、クラスに要求されたときに、サービスの同じインスタンスか別のインスタンスを提供します。Depending on how the lifetime of an operations service is configured for the following interfaces, the container provides either the same or a different instance of the service when requested by a class:

public interface IOperation
{
    Guid OperationId { get; }
}

public interface IOperationTransient : IOperation
{
}

public interface IOperationScoped : IOperation
{
}

public interface IOperationSingleton : IOperation
{
}

public interface IOperationSingletonInstance : IOperation
{
}

インターフェイスは Operation クラス内で実装されます。The interfaces are implemented in the Operation class. 指定されない場合、Operation コンストラクターは GUID を生成します。The Operation constructor generates a GUID if one isn't supplied:

public class Operation : IOperationTransient, 
    IOperationScoped, 
    IOperationSingleton, 
    IOperationSingletonInstance
{
    public Operation() : this(Guid.NewGuid())
    {
    }

    public Operation(Guid id)
    {
        OperationId = id;
    }

    public Guid OperationId { get; private set; }
}

OperationService が登録されます。これは、その他の Operation 型のそれぞれに依存します。An OperationService is registered that depends on each of the other Operation types. 依存関係の挿入を経由して OperationService が要求される場合、これは各サービスの新しいインスタンスか、依存関係のあるサービスの有効期間に基づく既存のインスタンスを受信します。When OperationService is requested via dependency injection, it receives either a new instance of each service or an existing instance based on the lifetime of the dependent service.

  • コンテナーからの要求時に一時的なサービスが作成されるとき、IOperationTransient サービスの OperationIdOperationServiceOperationId は異なります。When transient services are created when requested from the container, the OperationId of the IOperationTransient service is different than the OperationId of the OperationService. OperationServiceIOperationTransient クラスの新しいインスタンスを受け取ります。OperationService receives a new instance of the IOperationTransient class. 新しいインスタンスは異なる OperationId を生成します。The new instance yields a different OperationId.
  • クライアント要求ごとにスコープ サービスが作成されるとき、IOperationScoped サービスの OperationId は、クライアント要求内の OperationService のものと同じになります。When scoped services are created per client request, the OperationId of the IOperationScoped service is the same as that of OperationService within a client request. クライアント要求間で、両方のサービスは異なる OperationId 値を共有します。Across client requests, both services share a different OperationId value.
  • シングルトンとシングルトン インスタンスのサービスが 1 回作成され、すべてのクライアント要求とすべてのサービス間で使用されるとき、OperationId はすべてのサービス要求の間で一定です。When singleton and singleton-instance services are created once and used across all client requests and all services, the OperationId is constant across all service requests.
public class OperationService
{
    public OperationService(
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance instanceOperation)
    {
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = instanceOperation;
    }

    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }
}

Startup.ConfigureServices では、各型が名前で指定されている有効期間に従ってコンテナーに追加されます。In Startup.ConfigureServices, each type is added to the container according to its named lifetime:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));

    // OperationService depends on each of the other Operation types.
    services.AddTransient<OperationService, OperationService>();
}

IOperationSingletonInstance サービスは、Guid.Empty の既知の ID を持った特定のインスタンスを使用しています。The IOperationSingletonInstance service is using a specific instance with a known ID of Guid.Empty. この型が使用されるタイミングは明らかです (その GUID はすべてゼロです)。It's clear when this type is in use (its GUID is all zeroes).

サンプル アプリでは、個々の要求内、および個々の要求間におけるオブジェクトの有効期間が示されます。The sample app demonstrates object lifetimes within and between individual requests. サンプル アプリの IndexModel には、各種類の IOperation 型と OperationService が必要です。The sample app's IndexModel requests each kind of IOperation type and the OperationService. 次に、ページ モデル クラスとサービスのすべての OperationId 値が、プロパティの割り当てを通じてページに表示されます。The page then displays all of the page model class's and service's OperationId values through property assignments:

public class IndexModel : PageModel
{
    private readonly IMyDependency _myDependency;

    public IndexModel(
        IMyDependency myDependency, 
        OperationService operationService,
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance singletonInstanceOperation)
    {
        _myDependency = myDependency;
        OperationService = operationService;
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = singletonInstanceOperation;
    }

    public OperationService OperationService { get; }
    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }

    public async Task OnGetAsync()
    {
        await _myDependency.WriteMessage(
            "IndexModel.OnGetAsync created this message.");
    }
}

2 つの要求の結果を、以下の 2 つの出力に示します。Two following output shows the results of two requests:

最初の要求:First request:

コントローラーの操作:Controller operations:

一時的: d233e165-f417-469b-a866-1cf1935d2518Transient: d233e165-f417-469b-a866-1cf1935d2518
スコープ:5d997e2d-55f5-4a64-8388-51c4e3a1ad19Scoped: 5d997e2d-55f5-4a64-8388-51c4e3a1ad19
シングルトン:01271bc1-9e31-48e7-8f7c-7261b040ded9Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9
インスタンス:00000000-0000-0000-0000-000000000000Instance: 00000000-0000-0000-0000-000000000000

OperationService の操作:OperationService operations:

一時的: c6b049eb-1318-4e31-90f1-eb2dd849ff64Transient: c6b049eb-1318-4e31-90f1-eb2dd849ff64
スコープ:5d997e2d-55f5-4a64-8388-51c4e3a1ad19Scoped: 5d997e2d-55f5-4a64-8388-51c4e3a1ad19
シングルトン:01271bc1-9e31-48e7-8f7c-7261b040ded9Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9
インスタンス:00000000-0000-0000-0000-000000000000Instance: 00000000-0000-0000-0000-000000000000

2 番目の要求:Second request:

コントローラーの操作:Controller operations:

一時的: b63bd538-0a37-4ff1-90ba-081c5138dda0Transient: b63bd538-0a37-4ff1-90ba-081c5138dda0
スコープ:31e820c5-4834-4d22-83fc-a60118acb9f4Scoped: 31e820c5-4834-4d22-83fc-a60118acb9f4
シングルトン:01271bc1-9e31-48e7-8f7c-7261b040ded9Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9
インスタンス:00000000-0000-0000-0000-000000000000Instance: 00000000-0000-0000-0000-000000000000

OperationService の操作:OperationService operations:

一時的: c4cbacb8-36a2-436d-81c8-8c1b78808aafTransient: c4cbacb8-36a2-436d-81c8-8c1b78808aaf
スコープ:31e820c5-4834-4d22-83fc-a60118acb9f4Scoped: 31e820c5-4834-4d22-83fc-a60118acb9f4
シングルトン:01271bc1-9e31-48e7-8f7c-7261b040ded9Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9
インスタンス:00000000-0000-0000-0000-000000000000Instance: 00000000-0000-0000-0000-000000000000

要求内および要求間で、どの OperationId 値が変化しているかを確認してください。Observe which of the OperationId values vary within a request and between requests:

  • "一時的な" オブジェクトは常に異なります。Transient objects are always different. 1 番目と 2 番目のクライアント要求の一時的な OperationId 値は、OperationService 操作とクライアント要求間の両方に対して異なります。The transient OperationId value for both the first and second client requests are different for both OperationService operations and across client requests. 個々のサービス要求とクライアント要求に対して、新しいインスタンスが提供されます。A new instance is provided to each service request and client request.
  • Scoped オブジェクトは、1 つのクライアント要求内では同じですが、複数のクライアント要求間では異なります。Scoped objects are the same within a client request but different across client requests.
  • "シングルトン" オブジェクトは、Operation インスタンスが Startup.ConfigureServices で提供されるかどうかに関係なく、すべてのオブジェクトとすべての要求について同じです。Singleton objects are the same for every object and every request regardless of whether an Operation instance is provided in Startup.ConfigureServices.

main からサービスを呼び出すCall services from main

IServiceScopeFactory.CreateScope を使用して IServiceScope を作成し、アプリのスコープ内のスコープ サービスを解決します。Create an IServiceScope with IServiceScopeFactory.CreateScope to resolve a scoped service within the app's scope. この方法は、起動時に初期化タスクを実行するために、スコープ サービスにアクセスするのに便利です。This approach is useful to access a scoped service at startup to run initialization tasks. 次の例では、Program.MainMyScopedService のコンテキストを取得する方法を示します。The following example shows how to obtain a context for the MyScopedService in Program.Main:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();

        using (var serviceScope = host.Services.CreateScope())
        {
            var services = serviceScope.ServiceProvider;

            try
            {
                var serviceContext = services.GetRequiredService<MyScopedService>();
                // Use the context here
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred.");
            }
        }

        await host.RunAsync();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

スコープの検証Scope validation

アプリが開発環境で実行されている場合、既定のサービス プロバイダーは次を確認するためのチェックを実行します。When the app is running in the Development environment, the default service provider performs checks to verify that:

  • スコープ サービスが、ルート サービス プロバイダーによって直接的または間接的に解決されない。Scoped services aren't directly or indirectly resolved from the root service provider.
  • スコープ サービスが、シングルトンに直接または間接に挿入されない。Scoped services aren't directly or indirectly injected into singletons.

BuildServiceProvider が呼び出されると、ルート サービス プロバイダーが作成されます。The root service provider is created when BuildServiceProvider is called. ルート サービス プロバイダーの有効期間は、プロバイダーがアプリで開始されるとアプリとサーバーの有効期間に対応し、アプリのシャットダウンには破棄されます。The root service provider's lifetime corresponds to the app/server's lifetime when the provider starts with the app and is disposed when the app shuts down.

スコープ サービスは、それを作成したコンテナーによって破棄されます。Scoped services are disposed by the container that created them. ルート コンテナーにスコープ サービスが作成されると、サービスはアプリ/サーバーのシャットダウン時に、ルート コンテナーによってのみ破棄されるため、サービスの有効期間は実質的にシングルトンに昇格されます。If a scoped service is created in the root container, the service's lifetime is effectively promoted to singleton because it's only disposed by the root container when app/server is shut down. BuildServiceProvider が呼び出されると、サービス スコープの検証がこれらの状況をキャッチします。Validating service scopes catches these situations when BuildServiceProvider is called.

詳細については、「ASP.NET Core の Web ホスト」を参照してください。For more information, see ASP.NET Core の Web ホスト.

要求サービスRequest Services

HttpContext からの ASP.NET Core 要求内で使用可能なサービスは、HttpContext.RequestServices コレクションを通じて公開されます。The services available within an ASP.NET Core request from HttpContext are exposed through the HttpContext.RequestServices collection.

要求サービスは、アプリの一部として構成および要求されるサービスを表します。Request Services represent the services configured and requested as part of the app. オブジェクトで依存関係を指定すると、これらは ApplicationServices ではなく RequestServices で検出された型で満たされます。When the objects specify dependencies, these are satisfied by the types found in RequestServices, not ApplicationServices.

一般に、アプリから直接これらのプロパティを使用しないでください。Generally, the app shouldn't use these properties directly. 代わりに、クラスのコンストラクターを介してクラスに必要な型を要求し、フレームワークに依存関係を挿入させます。Instead, request the types that classes require via class constructors and allow the framework inject the dependencies. これにより、テストしやすいクラスが生成されます。This yields classes that are easier to test.

注意

コンストラクターのパラメーターとして依存関係を要求し、RequestServices コレクションにアクセスするようにします。Prefer requesting dependencies as constructor parameters to accessing the RequestServices collection.

依存関係の挿入のためのサービスの設計Design services for dependency injection

ベスト プラクティスは次のとおりです。Best practices are to:

  • 各依存関係を取得するために依存関係の挿入を使用するようサービスを設計します。Design services to use dependency injection to obtain their dependencies.
  • ステートフル、静的クラス、およびメンバーは避けてください。Avoid stateful, static classes and members. 代わりにシングルトン サービスを使用するようにアプリを設計し、グローバルな状態を作成しないようにします。Design apps to use singleton services instead, which avoid creating global state.
  • サービス内部で依存関係のあるクラスを直接インスタンス化することを回避します。Avoid direct instantiation of dependent classes within services. 直接のインスタンス化は、コードの固有の実装につながります。Direct instantiation couples the code to a particular implementation.
  • アプリのクラスを、小さく、十分に要素に分割された、テストしやすいものにします。Make app classes small, well-factored, and easily tested.

クラスに含まれる挿入される依存関係が多すぎるように見える場合、これは通常、クラスが担当する役割が多すぎて、単一責任の原則 (SRP) に違反していることのサインです。If a class seems to have too many injected dependencies, this is generally a sign that the class has too many responsibilities and is violating the Single Responsibility Principle (SRP). 責任の一部を新しいクラスに移動することにより、クラスのリファクタリングを試みます。Attempt to refactor the class by moving some of its responsibilities into a new class. Razor Pages のページ モデル クラスと MVC コントローラー クラスは、UI の問題に集中する必要があることに留意します。Keep in mind that Razor Pages page model classes and MVC controller classes should focus on UI concerns. ビジネス ルールとデータ アクセスの実装の詳細は、これらの個別の問題に適したクラスに分離する必要があります。Business rules and data access implementation details should be kept in classes appropriate to these separate concerns.

サービスの破棄Disposal of services

コンテナーは、作成する IDisposable 型の Dispose を呼び出します。The container calls Dispose for the IDisposable types it creates. ユーザー コードによってコンテナーに追加されたインスタンスは、自動的に破棄されません。If an instance is added to the container by user code, it isn't disposed automatically.

次の例では、サービスがサービス コンテナーによって作成され、自動的に破棄されます。In the following example, the services are created by the service container and disposed automatically:

public class Service1 : IDisposable {}
public class Service2 : IDisposable {}

public interface IService3 {}
public class Service3 : IService3, IDisposable {}

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<Service1>();
    services.AddSingleton<Service2>();
    services.AddSingleton<IService3>(sp => new Service3());
}

次に例を示します。In the following example:

  • サービス インスタンスは、サービス コンテナーによって作成されるわけではありません。The service instances aren't created by the service container.
  • サービスの有効期間は、フレームワークによって認識されません。The intended service lifetimes aren't known by the framework.
  • フレームワークでは、サービスが自動的に破棄されることはありません。The framework doesn't dispose of the services automatically.
  • サービスが開発者コードで明示的に破棄されていない場合は、アプリがシャットダウンするまで保持されます。If the services aren't explicitly disposed in developer code, they persist until the app shuts down.
public class Service1 : IDisposable {}
public class Service2 : IDisposable {}

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<Service1>(new Service1());
    services.AddSingleton(new Service2());
}

一時的なインスタンスと共有インスタンスのための IDisposable ガイダンスIDisposable guidance for Transient and shared instances

一時的で限定的な有効期間Transient, limited lifetime

シナリオScenario

アプリには、次のいずれかのシナリオに対して一時的な有効期間を持つ IDisposable インスタンスが必要です。The app requires an IDisposable instance with a transient lifetime for either of the following scenarios:

  • インスタンスは、ルート スコープで解決されます。The instance is resolved in the root scope.
  • インスタンスは、スコープが終了する前に破棄する必要があります。The instance should be disposed before the scope ends.

解決方法Solution

ファクトリ パターンを使用して、親スコープの外部にインスタンスを作成します。Use the factory pattern to create an instance outside of the parent scope. このような状況では、通常、アプリケーションには、最終的な型のコンストラクターを直接呼び出す Create メソッドがあります。In this situation, the app would generally have a Create method that calls the final type's constructor directly. 最終的な型に他の依存関係がある場合、ファクトリは次のことができます。If the final type has other dependencies, the factory can:

共有インスタンス、限定的な有効期間Shared Instance, limited lifetime

シナリオScenario

アプリでは、複数のサービスにわたって共有 IDisposable インスタンスが必要ですが、IDisposable の有効期間は限られています。The app requires a shared IDisposable instance across multiple services, but the IDisposable should have a limited lifetime.

解決方法Solution

インスタンスをスコープ付きの有効期間に登録します。Register the instance with a Scoped lifetime. IServiceScopeFactory.CreateScope を使用してを開始し、新しい IServiceScope を作成します。Use IServiceScopeFactory.CreateScope to start and create a new IServiceScope. スコープの IServiceProvider を使用して必要なサービスを取得します。Use the scope's IServiceProvider to get required services. 有効期間が終了するときにスコープを破棄します。Dispose the scope when the lifetime should end.

一般的なガイドラインGeneral Guidelines

  • IDisposable インスタンスは、一時的なスコープを使用して登録しないでください。Don't register IDisposable instances with a Transient scope. 代わりに、ファクトリ パターンを使用します。Use the factory pattern instead.
  • 一時的またはスコープ付きの IDisposable インスタンスをルート スコープ内で解決しないでください。Don't resolve Transient or Scoped IDisposable instances in the root scope. 唯一の一般的な例外は、アプリが IServiceProvider を作成/再作成し、破棄する場合です。これは理想的なパターンではありません。The only general exception is when the app creates/recreates and disposes the IServiceProvider, which isn't an ideal pattern.
  • DI を使用して IDisposable 依存関係を受け取る場合、受信側が IDisposable 自体を実装する必要はありません。Receiving an IDisposable dependency via DI doesn't require that the receiver implement IDisposable itself. IDisposable 依存関係の受信側は、その依存関係で Dispose を呼び出してはなりません。The receiver of the IDisposable dependency shouldn't call Dispose on that dependency.
  • サービスの有効期間を制御するには、スコープを使用する必要があります。Scopes should be used to control lifetimes of services. スコープは階層構造ではなく、スコープ間に特別な接続はありません。Scopes aren't hierarchical, and there's no special connection among scopes.

既定のサービス コンテナーの置換Default service container replacement

組み込みのサービス コンテナーは、フレームワークと、ほとんどのコンシューマー アプリのニーズに対応することを目的としたものです。The built-in service container is designed to serve the needs of the framework and most consumer apps. 組み込みコンテナーでサポートされない、以下のような特定の機能が必要な場合を除き、組み込みコンテナーを使用することをお勧めします。We recommend using the built-in container unless you need a specific feature that the built-in container doesn't support, such as:

  • プロパティの挿入Property injection
  • 名前に基づく挿入Injection based on name
  • 子コンテナーChild containers
  • 有効期間のカスタム管理Custom lifetime management
  • 遅延初期化に対する Func<T> のサポートFunc<T> support for lazy initialization
  • 規則に基づく登録Convention-based registration

次のサードパーティ コンテナーは ASP.NET Core アプリで使用できます。The following third-party containers can be used with ASP.NET Core apps:

スレッド セーフThread safety

スレッド セーフのシングルトン サービスを作成します。Create thread-safe singleton services. シングルトン サービスに一時的サービスへの依存関係がある場合、シングルトンによる一時的サービスの使い方によっては、一時的サービスもスレッド セーフであることが必要な場合があります。If a singleton service has a dependency on a transient service, the transient service may also require thread safety depending how it's used by the singleton.

1 つのサービスのファクトリ メソッド (例: AddSingleton<TService>(IServiceCollection, Func<IServiceProvider,TService>) に対する 2 番目の引数) をスレッド セーフにする必要はありません。The factory method of single service, such as the second argument to AddSingleton<TService>(IServiceCollection, Func<IServiceProvider,TService>), doesn't need to be thread-safe. 型 (static) のコンストラクターのように、1 つのスレッドによって 1 回呼び出されることが保証されます。Like a type (static) constructor, it's guaranteed to be called once by a single thread.

推奨事項Recommendations

  • async/await および Task ベースのサービスの解決はサポートされていません。async/await and Task based service resolution is not supported. C# では非同期コンストラクターがサポートされていないため、推奨パターンは、サービスを同期的に解決した後に、非同期メソッドを使用することです。C# does not support asynchronous constructors; therefore, the recommended pattern is to use asynchronous methods after synchronously resolving the service.

  • データと構成をサービス コンテナーに直接格納しないようにします。Avoid storing data and configuration directly in the service container. たとえば、通常、ユーザーのショッピング カートはサービス コンテナーに追加しません。For example, a user's shopping cart shouldn't typically be added to the service container. 構成では、オプション パターンを使う必要があります。Configuration should use the options pattern. 同様に、他のオブジェクトへのアクセスを許可するためだけに存在する "データ ホルダー" オブジェクトは避ける必要があります。Similarly, avoid "data holder" objects that only exist to allow access to some other object. 実際のアイテムを DI 経由で要求することをお勧めします。It's better to request the actual item via DI.

  • サービスへの静的なアクセスを行わないようにします。Avoid static access to services. たとえば、他の場所で使用するために IApplicationBuilder.ApplicationServices の静的な型指定を行わないようにします。For example, avoid statically-typing IApplicationBuilder.ApplicationServices for use elsewhere.

  • サービス ロケーター パターン は、制御の反転戦略が混在しているので使用しないでください。Avoid using the service locator pattern, which mixes Inversion of Control strategies.

    • サービス インスタンスを取得する場合、DI を使用できるときに、GetService を呼び出さないでください。Don't invoke GetService to obtain a service instance when you can use DI instead:

      正しくない:Incorrect:

      public class MyClass()
      
        public void MyMethod()
        {
            var optionsMonitor = 
                _services.GetService<IOptionsMonitor<MyOptions>>();
            var option = optionsMonitor.CurrentValue.Option;
      
            ...
        }
      

      正しい:Correct:

      public class MyClass
      {
          private readonly IOptionsMonitor<MyOptions> _optionsMonitor;
      
          public MyClass(IOptionsMonitor<MyOptions> optionsMonitor)
          {
              _optionsMonitor = optionsMonitor;
          }
      
          public void MyMethod()
          {
              var option = _optionsMonitor.CurrentValue.Option;
      
              ...
          }
      }
      
  • GetService を使用して、実行時に依存関係を解決するファクトリを挿入しないでください。Avoid injecting a factory that resolves dependencies at runtime using GetService.

  • HttpContext への静的なアクセスを回避します (たとえば IHttpContextAccessor.HttpContext)。Avoid static access to HttpContext (for example, IHttpContextAccessor.HttpContext).

どのような推奨事項であっても、それを無視する必要がある状況が発生する可能性があります。Like all sets of recommendations, you may encounter situations where ignoring a recommendation is required. 例外はまれです。ほとんどがフレームワーク自体の内の特殊なケースです。Exceptions are rare, mostly special cases within the framework itself.

DI は静的/グローバル オブジェクト アクセス パターンの 代替機能 です。DI is an alternative to static/global object access patterns. 静的オブジェクト アクセスと併用した場合、DI のメリットを実現することはできません。You may not be able to realize the benefits of DI if you mix it with static object access.

その他の技術情報Additional resources