Asp.NetのCoreで**依存性注入`**を実装したいです。そこで、ConfigureServices`***メソッドにこのコードを追加したところ、両方の方法で動作するようになりました。
Asp.Net Coreのservices.AddTransient
メソッドとservice.AddScoped
メソッドの違いは何ですか?
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddScoped<IEmailSender, AuthMessageSender>();
}
TL;DR
トランジェントなオブジェクトは常に異なるものであり、新しいインスタンスが提供され 全てのコントローラー、全てのサービスに対応します。 >; スコープされたオブジェクトは、リクエスト内では同じですが、サービス内では異なります。 さまざまなご要望にお応えします。 >; シングルトンオブジェクトは、すべてのオブジェクトとすべてのリクエストに対して同じです。
より明確にするために、asp.net docsのこの例では、その違いを示しています:
これらの寿命と登録オプションの違いを示すために、一意な識別子 OperationId
を持つ操作として1つまたは複数のタスクを表現するシンプルなインターフェイスを考えてみます。このサービスのライフタイムをどのように設定するかによって、コンテナはサービスの同じインスタンスまたは異なるインスタンスを要求元のクラスに提供することになります。どのライフタイムが要求されているかを明確にするために、ライフタイムオプションごとに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
{
}
}
このクラスはコンストラクタで Guid
を受け取り、もし何も与えられなかったら新しい Guid
を使用します:
using System;
using DependencyInjectionSample.Interfaces;
namespace DependencyInjectionSample.Classes
{
public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance
{
Guid _guid;
public Operation() : this(Guid.NewGuid())
{
}
public Operation(Guid guid)
{
_guid = guid;
}
public Guid OperationId => _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である特定のインスタンスを使用しているため、このタイプが使用されていることが明確になることに注意してください。また、他の
Operationタイプに依存する
OperationService` を登録し、このサービスがコントローラと同じインスタンスを取得しているか、新しいインスタンスを取得しているかがリクエスト内で明確になるようにしました。このサービスが行うことは、依存関係をプロパティとして公開し、ビューに表示できるようにすることだけです。
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;
}
}
}
アプリケーションへの個別のリクエスト内とリクエスト間のオブジェクトの寿命を示すために、このサンプルでは IOperation
タイプをリクエストする OperationsController
と 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つの別々のリクエストが行われたことになります: [最初のリクエスト][2]です。
[[2回目のリクエスト]][3回目][3回目]です。
OperationId`のどの値がリクエスト内、およびリクエスト間で変化するかを観察する。
トランジェントオブジェクトは常に異なるものであり、すべてのコントローラとすべてのサービスに新しいインスタンスが提供される。
スコープされたオブジェクトは、リクエスト内では同じだが、異なるリクエスト間では異なる。
シングルトン・オブジェクトは、すべてのオブジェクトとすべてのリクエストで同じです(ConfigureServices
でインスタンスが提供されているかどうかに関係なく)。
dotnetの依存性注入では、3つの主要なライフタイムがあります:
アプリケーション全体で単一のインスタンスを作成するSingletonです。初回にインスタンスを作成し、すべての呼び出しで同じオブジェクトを再利用します。
スコープされたライフタイムサービスは、スコープ内のリクエストごとに1回作成されます。例えばMVCでは、各Httpリクエストごとに1つのインスタンスが作成されますが、同じWebリクエスト内の他の呼び出しでは同じインスタンスを使用します。
Transientライフタイムのサービスは、要求されるたびに作成されます。このライフタイムは、軽量でステートレスなサービスに最適です。
ここでは、違いを見るために見つけることができ、例です:
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/
そして、これは公式ドキュメントへのリンクです:
-シングルトンは、アプリケーションの存続期間の単一のインスタンスです。 ドメイン。 -Scopedは、scopedの期間中の単一のインスタンスです。 リクエスト、つまりASP.NETの HTTP リクエストごと。 -トランジェントは、_code_リクエストごとの単一のインスタンスです。
通常、コードリクエストは、次のようにコンストラクターパラメーターを介して行う必要があります。
public MyConsumingClass(IDependency dependency)
@akazemisの回答で、DIのコンテキストでの「サービス」はRESTfulサービスを意味するものではないことを指摘したいと思います。サービスは、機能を提供する依存関係の実装です。
ASP.NET MVCコアDIでは、同じ型の複数のオブジェクトを注入しなければならない場合に、Transient、scoped、singletonでオブジェクト生成処理を定義します。依存性注入が初めての方は、こちらの[DI IOCビデオ][1]をご覧ください。
以下のコントローラコードでは、コンストラクタで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
}
}
Transient :- Transientでは、新しいオブジェクトのインスタンスが1つのRequestとResponseに注入されます。以下は、GUID値を表示したスナップショット画像です。
Scoped : - Scopedでは、同じオブジェクトのインスタンスが1つのリクエストとレスポンスに注入されます。
シングルトン: - シングルトンでは、同じオブジェクトがすべてのリクエストとレスポンスにわたって注入されます。この場合、オブジェクトのグローバルなインスタンスが1つ作成されます。
以下は、上記の基本的なことを視覚的に説明する簡単な図である。
上の画像は、私がASP.NET MVC training in mumbai トレーニングを受けたときにSBSSチームが描いたもので、上の画像を作成してくれたSBSSチームに感謝します。
AddSingleton()は、最初に要求されたときにサービスの単一のインスタンスを作成し、そのサービスが必要なすべての場所で同じインスタンスを再利用します。
すべてのhttpリクエストを含むスコープサービスでは、新しいインスタンスを取得します。 ただし、同じhttpリクエストでは、ビューやコントローラーなどの複数の場所でサービスが必要な場合は、そのhttpリクエストの全範囲に同じインスタンスが提供されます。 ただし、すべての新しいhttpリクエストには、サービスの新しいインスタンスが表示されます。
一時的なサービスでは、サービスインスタンスが同じhttpリクエストの範囲内にあるか、異なるhttpリクエスト全体にあるかにかかわらず、サービスインスタンスがリクエストされるたびに新しいインスタンスが提供されます。
この質問の答えを探した後、私はあなたと共有したい例を含む素晴らしい説明を見つけました。
[ HERE ][1]の違いを示すビデオを見ることができます。
この例では、次のコードがあります。
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>();
}
このコードをコピーして貼り付け、ビューの作成ボタンを押して切り替えます。
AddSingleton
、 AddScoped
、および AddTransient
は、この説明を理解するのに役立つ可能性のある異なる結果を毎回取得します。
AddSingleton()-名前が示すように、AddSingleton()メソッドはaを作成します。 シングルトンサービス。 シングルトンサービスは、最初のときに作成されます。 リクエスト。 この同じインスタンスが後続のすべてのインスタンスで使用されます。 リクエスト。 したがって、一般に、シングルトンサービスは1回だけ作成されます。 アプリケーションごとに、その単一のインスタンスが全体で使用されます。 アプリケーションの寿命。 。 AddTransient()-このメソッドはTransientサービスを作成します。 新しい。 Transientサービスのインスタンスは、リクエストされるたびに作成されます。 。 。 AddScoped()-このメソッドはScopedサービスを作成します。 新しいインスタンス。 スコープされたサービスは、リクエストごとにスコープ内で1回作成されます。 ために。 たとえば、Webアプリケーションでは、各httpごとに1つのインスタンスを作成します。 リクエストしますが、同じインスタンス内の他の呼び出しで同じインスタンスを使用します。 ウェブリクエスト。
[1]:https://www.youtube.com/watch?v = v6Nr7Zman_Y& list = PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU& index = 44。
ここ(このリンクは非常に便利です)で説明されているように、例を示します。
インターフェイスと具体的なタイプの間のこのマッピングは、IContryServiceのタイプをリクエストするたびに、CountryServiceの新しいインスタンスを取得することを定義しています。 この場合、これが一時的な意味です。 シングルトンマッピング(AddSingletonを使用)とスコープマッピング(AddScopedを使用)を追加することもできます。 この場合のスコープとは、HTTPリクエストにスコープすることを意味します。これは、現在のリクエストの実行中にシングルトンになることも意味します。 AddInstanceメソッドを使用して、既存のインスタンスをDIコンテナに追加することもできます。 これらは、IServiceCollectionに登録するためのほぼ完全な方法です。