سرویس هایی که به عنوان Transient رجیستر میشوند همیشه متفاوت هستند. یعنی به ازای هربار فراخوانی سرویس, یک نمونه جدید از شی ایجاد شده و در اختیار DI قرار داده میشود.

سرویس هایی که به عنوان Scoped رجیستر میشوند به ازای هر ریکوست یک شی در اختیار DI قرار میگیرد.

سرویس هایی که به عنوان Singleton رجیستر میشوند در اولین درخواست یک شی از کلاس مورد نظر در اختیار DI قرار میگیرد و در درخواست های بعدی همان شی در اختیار DI قرار میگیرد.

برای نشان دادن تفاوت عملکرد بین این طول عمرها ، یک اینترفیس ساده را در نظر بگیرید که یک پراپرتی از نوع GUID دارد و کلاسی که از این اینترفیس ارث بری میکند در سازنده خود مقدار پراپرتی GUID را مقدار دهی اولیه میکند. در ادامه سه اینترفیس با نام های IOperationTtansient, IOperationScoped  و  IOperationSingleton معرفی میکنیم که هر کدام از IOperation ارث بری میکنند. سپس هر چهار اینترفیس را با طول عمرهای مختلف رجیستر میکنیم و تفاوت بین این طول عمرها نشان داده خواهد شد.

public interface IOperation
{
    Guid OperationId { get; }
}

public interface IOperationTransient : IOperation
{
}

public interface IOperationScoped : IOperation
{
}

public interface IOperationSingleton : IOperation
{
}

در ادامه کلاسی که از این اینترفیس ها ارث بری کرده را به صورت زیر پیاده سازی میکنیم

public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton
{
    Guid _guid;
    public Operation()
    {
        _guid = Guid.NewGuid();
    }

    public Guid OperationId => _guid;
}

در ادامه یک کلاس برای نشان دادن تفاوت بین Scoped و Transient پیاده سازی میکنیم که فقط سرویس هارا از کانستراکتور دریافت کرده و مقدار دهی اولیه را انجام میدهد.

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

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

و در ادامه کلاسها را در DI رجیستر میکنیم.

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

سپس در کنترلر از طریق DI سرویس هارا دریافت میکنیم و در ویو مقدار GUID را نشان میدهیم.

public class HomeController : Controller
{
    private readonly OperationService _operationService;
    private readonly IOperationTransient _transientOperation;
    private readonly IOperationScoped _scopedOperation;
    private readonly IOperationSingleton _singletonOperation;

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

    public IActionResult Index()
    {
        ViewBag.Transient = _transientOperation;
        ViewBag.Scoped = _scopedOperation;
        ViewBag.Singleton = _singletonOperation;
        ViewBag.Service = _operationService;
        return View();
    }
}

کد ویو

@{
    IOperationTransient operationTransient = (IOperationTransient)ViewBag.Transient;
    IOperationScoped operationScoped = (IOperationScoped)ViewBag.Scoped;
    IOperationSingleton operationSingleton = (IOperationSingleton)ViewBag.Singleton;
    OperationService operationService = (OperationService)ViewBag.Service;
}
<div>
    <p>Scoped : @operationScoped.OperationId</p>
    <p>Transient : @operationTransient.OperationId</p>
    <p>Singleton : @operationSingleton.OperationId</p>
</div>

<p>Operation Service</p>
<div>
    <p>Scoped : @operationService.ScopedOperation.OperationId</p>
    <p>Transient : @operationService.TransientOperation.OperationId</p>
    <p>Singleton : @operationService.SingletonOperation.OperationId</p>
</div>

و در نهایت در ویو خروجی زیر نشان داده خواهد شد.

درخواست اول :

Scoped : cc0de4ac-0aaf-4e18-8a66-7c9672384f7b

Transient : 853f0faa-658e-4d9e-8288-99656636a96d

Singleton : 94e426e4-ec53-4665-949c-07eaf2f76dad

Operation Service

Scoped : cc0de4ac-0aaf-4e18-8a66-7c9672384f7b

Transient : 11e27e2e-1ecf-4fb7-b90f-6aace02121a4

Singleton : 94e426e4-ec53-4665-949c-07eaf2f76dad

درخواست دوم :

Scoped : d9f085f5-f72f-4eea-bf70-d490a602e80d

Transient : 11bab21a-032e-4eb5-8d5f-fd86ea19a640

Singleton : 94e426e4-ec53-4665-949c-07eaf2f76dad

Operation Service

Scoped : d9f085f5-f72f-4eea-bf70-d490a602e80d

Transient : 12f7a9a6-a38f-4abd-aef3-9cef25bb2732

Singleton : 94e426e4-ec53-4665-949c-07eaf2f76dad

کلاسی که از نوع Singleton رجیستر شده است در درخواست اول مقداردهی اولیه میشود و در درخواست های بعدی همان مقدار را نشان میدهد.

اما کلاسی که از نوع Scoped رجیستر شده است به ازای هر ریکوست یک مقدار جدید نشان میدهد.

و در کلاسی که از نوع Transient رجیستر شده است به ازای هر درخواست کلاس یک مقدار جدید نمایش میدهد.

 در این مثال هر کدام از سرویس ها دوبار از طریق DI فراخوانی شده اند. یکبار در کنترلر و یکبار در کلاس OperationService اما Scoped فقط یک مقدار را نشان میدهد در هر درخواست ولی Transient به ازای هر بار فراخوانی یک مقدار جدید را نشان میدهد.

Powered by Froala Editor

نظرات

سایر نظرات
  • علیرضاسیف

    سلاممن برنامه ران می کنم این خطا دریافت میکنمMultiple constructors accepting all given argument types have been found in type 'HomeController'. There should only be one applicable constructor.

    ارسال شده در تاریخ دوشنبه، ۲۸ آذر ۱۴۰۱
    • admin

      سلام وقت بخیر. خطای مربوطه برای وجود چند سازنده در HomeController می باشد. تنها باید یک سازنده در HomeController وجود داشته باشد.

      ارسال شده در تاریخ جمعه، ۰۲ دی ۱۴۰۱