web-dev-qa-db-ja.com

AddTransient、AddScopedおよびAddSingletonサービスの違いは?

dependency injectionAsp.Net Coreを実装したい。したがって、このコードをConfigureServicesmethodに追加した後は、両方の方法でうまくいきます。

services.AddTransientservice.AddScopeの違いは何ですかAsp.Net Core

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddScoped<IEmailSender, AuthMessageSender>();
}
531
Elvin Mammadov

TL; DR

一時的なオブジェクトは常に異なります。新しいインスタンスがすべてのコントローラとすべてのサービスに提供されます。

スコープ付きオブジェクトはリクエスト内では同じですが、リクエストごとに異なります。

シングルトンオブジェクトは、すべてのオブジェクトとすべての要求に対して同じです。

より明確にするために、 asp.net docs からの次の例は違いを示しています。

これらの有効期間オプションと登録オプションの違いを説明するために、1つ以上のタスクを一意の識別子OperationIdを持つ操作として表す単純なインターフェイスを検討してください。このサービスの有効期間をどのように設定したかに応じて、コンテナは要求しているクラスにサービスの同じまたは異なるインスタンスを提供します。どのライフタイムが要求されているかを明確にするために、ライフタイムオプションごとに1つのタイプを作成します。

using System;

namespace DependencyInjectionSample.Interfaces
{
    public interface IOperation
    {
        Guid OperationId { get; }
    }

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

これらのインタフェースは、コンストラクタ内でOperationを受け入れる単一のクラスGuidを使用して実装するか、または何も提供されていない場合は新しいGuidを使用します。

次に、ConfigureServicesでは、それぞれの型はその名前付き寿命に従ってコンテナに追加されます。

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

IOperationSingletonInstanceサービスは既知のID Guid.Emptyを持つ特定のインスタンスを使用しているので、このタイプが使用されているときは明らかになります。他のOperationService型のそれぞれに依存するOperationも登録したので、このサービスが各操作型に対してコントローラと同じインスタンスを取得するのか、新しいインスタンスを取得するのかがリクエスト内で明確になります。このサービスが行うことは、依存関係をプロパティとして公開することだけなので、それらをビューに表示できます。

using DependencyInjectionSample.Interfaces;

namespace DependencyInjectionSample.Services
{
    public class OperationService
    {
        public IOperationTransient TransientOperation { get; }
        public IOperationScoped ScopedOperation { get; }
        public IOperationSingleton SingletonOperation { get; }
        public IOperationSingletonInstance SingletonInstanceOperation { get; }

        public OperationService(IOperationTransient transientOperation,
            IOperationScoped scopedOperation,
            IOperationSingleton singletonOperation,
            IOperationSingletonInstance instanceOperation)
        {
            TransientOperation = transientOperation;
            ScopedOperation = scopedOperation;
            SingletonOperation = singletonOperation;
            SingletonInstanceOperation = instanceOperation;
        }
    }
}

アプリケーションへの個別の個々の要求内およびその間のオブジェクトの存続期間を示すために、サンプルには各種類のOperationsController型とIOperationを要求するOperationServiceが含まれています。 Indexアクションは、コントローラとサービスのすべてのOperationId値を表示します。

using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
using Microsoft.AspNetCore.Mvc;

namespace DependencyInjectionSample.Controllers
{
    public class OperationsController : Controller
    {
        private readonly OperationService _operationService;
        private readonly IOperationTransient _transientOperation;
        private readonly IOperationScoped _scopedOperation;
        private readonly IOperationSingleton _singletonOperation;
        private readonly IOperationSingletonInstance _singletonInstanceOperation;

        public OperationsController(OperationService operationService,
            IOperationTransient transientOperation,
            IOperationScoped scopedOperation,
            IOperationSingleton singletonOperation,
            IOperationSingletonInstance singletonInstanceOperation)
        {
            _operationService = operationService;
            _transientOperation = transientOperation;
            _scopedOperation = scopedOperation;
            _singletonOperation = singletonOperation;
            _singletonInstanceOperation = singletonInstanceOperation;
        }

        public IActionResult Index()
        {
            // viewbag contains controller-requested services
            ViewBag.Transient = _transientOperation;
            ViewBag.Scoped = _scopedOperation;
            ViewBag.Singleton = _singletonOperation;
            ViewBag.SingletonInstance = _singletonInstanceOperation;

            // operation service has its own requested services
            ViewBag.Service = _operationService;
            return View();
        }
    }
}

これで、このコントローラアクションに対して2つの別々の要求が行われました。 First Request

Second Request

リクエスト内およびリクエスト間でどのOperationId値が異なるかを観察します。

  • 一時的なオブジェクトは常に異なります。新しいインスタンスがすべてのコントローラとすべてのサービスに提供されます。

  • スコープオブジェクトはリクエスト内では同じですが、異なるリクエスト間では異なります

  • シングルトンオブジェクトは、すべてのオブジェクトとすべての要求で同じです(インスタンスがConfigureServicesで提供されているかどうかにかかわらず)。

1008
akazemis

Dotnetの依存性注入には3つの主な寿命があります。

Singleton アプリケーション全体に単一のインスタンスを作成します。初めてインスタンスを作成し、すべての呼び出しで同じオブジェクトを再利用します。

有効範囲 有効期間内の要求ごとに1回サービスが作成されます。現在のスコープではSingletonと同じです。例えば。 MVCでは、httpリクエストごとに1つのインスタンスを作成しますが、同じWebリクエスト内の他の呼び出しでは同じインスタンスを使用します。

一時的 ライフタイムサービスは要求されるたびに作成されます。この寿命は、軽量のステートレスサービスに最適です。

ここであなたは違いを見るために見つけて例を見ることができます:

http://dotnetliberty.com/index.php/2015/10/15/asp-net-5-mvc6-dependency-injection-in-6-steps/ /

https://codewala.net/2015/04/30/your-dependency-injection-ready-asp-net-asp-net-5/ /

これは公式文書へのリンクです。

https://docs.asp.net/en/latest/fundamentals/dependency-injection.html#service-lifetimes-and-registration-options

246
akazemis
  • シングルトンは、アプリケーションドメインの存続​​期間中の単一のインスタンスです。
  • 有効範囲は、有効範囲が指定された要求の期間中の単一のインスタンスです。つまり、ASP.NETのHTTP要求ごとです。
  • トランジェントは、code要求ごとに1つのインスタンスです。

通常、コード要求は次のようにコンストラクタパラメータを介して行われます。

public MyConsumingClass(IDependency dependency)

@ akazemisの回答で、DIの文脈における「サービス」はRESTfulなサービスを暗示していないことを指摘したいと思いました。サービスは機能を提供する依存関係の実装です。

21
user1969177

同じタイプの複数のオブジェクトをインジェクトする必要がある場合、トランジェント、スコープおよびシングルトンはASP.NET MVCコアDIでオブジェクト作成プロセスを定義します。 Dependency injectionに慣れていない場合は、この{ DI IOC video を参照してください。

あなたは私がコンストラクタで "IDal"の2つのインスタンスを要求した以下のコントローラコードを見ることができます。 Transient、Scoped、およびSingletonは、同じインスタンスが "_dal"と "_dal1"でインジェクトされるのか、それとも異なるインスタンスでインジェクトされるのかを定義します。

public class CustomerController : Controller
    {
        IDal dal = null;
        public CustomerController(IDal _dal
                                ,IDal _dal1)
        {
            dal = _dal;
            // DI of MVC core
            // inversion of control
        }
}

トランジェント: - トランジェントで新しいオブジェクトインスタンスは単一のリクエストとレスポンスでインジェクトされます。以下はスナップショットイメージで、GUIDの値が表示されています。

enter image description here

スコープ: - スコープ内の同じオブジェクトインスタンスは単一のリクエストとレスポンスでインジェクトされます。

enter image description here

シングルトン: - シングルトンでは、同じオブジェクトがすべてのリクエストとレスポンスに渡って注入されます。この場合、オブジェクトのグローバルインスタンスが1つ作成されます。

以下は、上記の基本を視覚的に説明する簡単な図です。

MVC DI image

上記の画像は、SBSSチームが ムンバイでのASP.NET MVCトレーニング トレーニングを受けているときに作成したものです。

17

この質問の答えを探した後、私はあなたと共有したい例で素晴らしい説明を見つけました。

違いを示すビデオを見ることができます HERE

この例では、次のコードがあります。

public interface IEmployeeRepository
{
    IEnumerable<Employee> GetAllEmployees();
    Employee Add(Employee employee);
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MockEmployeeRepository : IEmployeeRepository
{
    private List<Employee> _employeeList;

    public MockEmployeeRepository()
    {
        _employeeList = new List<Employee>()
    {
        new Employee() { Id = 1, Name = "Mary" },
        new Employee() { Id = 2, Name = "John" },
        new Employee() { Id = 3, Name = "Sam" },
    };
    }

    public Employee Add(Employee employee)
    {
        employee.Id = _employeeList.Max(e => e.Id) + 1;
        _employeeList.Add(employee);
        return employee;
    }

    public IEnumerable<Employee> GetAllEmployees()
    {
        return _employeeList;
    }
}

HomeController

public class HomeController : Controller
{
    private IEmployeeRepository _employeeRepository;

    public HomeController(IEmployeeRepository employeeRepository)
    {
        _employeeRepository = employeeRepository;
    }

    [HttpGet]
    public ViewResult Create()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Create(Employee employee)
    {
        if (ModelState.IsValid)
        {
            Employee newEmployee = _employeeRepository.Add(employee);
        }

        return View();
    }
}

ビューの作成

@model Employee
@inject IEmployeeRepository empRepository

<form asp-controller="home" asp-action="create" method="post">
    <div>
        <label asp-for="Name"></label>
        <div>
            <input asp-for="Name">
        </div>
    </div>

    <div>
        <button type="submit">Create</button>
    </div>

    <div>
        Total Employees Count = @empRepository.GetAllEmployees().Count().ToString()
    </div>
</form>

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IEmployeeRepository, MockEmployeeRepository>();
}

このコードをコピーして貼り付け、ビューの作成ボタンを押して、AddSingletonAddScopedおよびAddTransientを切り替えます。この説明を理解するのに役立つさまざまな結果が得られます:

AddSingleton()-名前が示すように、AddSingleton()メソッドはシングルトンサービスを作成します。シングルトンサービスは、最初に要求されたときに作成されます。この同じインスタンスは、その後のすべてのリクエストで使用されます。そのため、一般に、シングルトンサービスはアプリケーションごとに1回だけ作成され、その単一のインスタンスはアプリケーションのライフタイムを通じて使用されます。

AddTransient()-このメソッドはTransientサービスを作成します。 Transientサービスの新しいインスタンスは、要求されるたびに作成されます。

AddScoped()-このメソッドは、Scopedサービスを作成します。スコープサービスの新しいインスタンスは、スコープ内のリクエストごとに1回作成されます。たとえば、Webアプリケーションでは、http要求ごとに1つのインスタンスを作成しますが、同じWeb要求内の他の呼び出しで同じインスタンスを使用します。

2
Offir Pe'er

例として here (このリンクはとても役に立ちます)のように、

インターフェースと具象型の間のこのマッピングは、IContryServiceの型を要求するたびに、CountryServiceの新しいインスタンスを取得することを定義しています。これはこの場合過渡的な意味です。また、シングルトンマッピング(AddSingletonを使用)とスコープマッピング(AddScopedを使用)を追加することもできます。この場合のスコープとは、HTTPリクエストにスコープされていることを意味します。つまり、現在のリクエストが実行されている間は、それがシングルトンであることも意味します。メソッドAddInstanceを使用して既存のインスタンスをDIコンテナに追加することもできます。これらはIServiceCollectionに登録するためのほぼ完全な方法です。

1
Rehmanali Momin

AddSingleton()

AddSingleton()は、最初に要求されたときにサービスの単一のインスタンスを作成し、そのサービスが必要なすべての場所でその同じインスタンスを再利用します。

AddScoped()

すべてのhttpリクエストを含むスコープサービスでは、新しいインスタンスを取得します。ただし、ビュー内およびコントローラ内などの複数の場所でサービスが必要な場合は、同じhttpリクエストでは、そのhttpリクエストのスコープ全体に対して同じインスタンスが提供されます。しかし、すべての新しいhttpリクエストはサービスの新しいインスタンスを取得します。

AddTransient()

一時サービスでは、サービスインスタンスが同じhttpリクエストの範囲内にあるか、異なるhttpリクエストにまたがるかにかかわらず、サービスインスタンスが要求されるたびに新しいインスタンスが提供されます。

0
Yasser