TL; DR
Obiekty przejściowe są zawsze różne; nowa instancja jest dostarczana do każdego kontrolera i każdej usługi.
Obiekty o zasięgu są takie same w żądaniu, ale różne dla różnych żądań.
Obiekty Singleton są takie same dla każdego obiektu i każdego żądania.
Aby uzyskać dodatkowe wyjaśnienia, ten przykład z dokumentacji ASP.NET pokazuje różnicę:
Aby wykazać różnicę między tymi opcjami życiowych i rejestracyjnych, rozważmy prosty interfejs, który stanowi jeden lub więcej zadań jako operacja z unikalnym identyfikatorem, OperationId
. W zależności od tego, w jaki sposób skonfigurujemy czas życia tej usługi, kontener zapewni klasę żądającą takie same lub różne wystąpienia usługi. Aby wyjaśnić, który okres istnienia jest wymagany, utworzymy jeden typ dla okresu istnienia:
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
{
}
}
Implementujemy te interfejsy za pomocą jednej klasy, Operation
która akceptuje identyfikator GUID w swoim konstruktorze lub używa nowego identyfikatora GUID, jeśli nie został podany:
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;
}
}
Następnie za ConfigureServices
każdy typ jest dodawany do kontenera zgodnie z jego nazwanym czasem życia:
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
services.AddTransient<OperationService, OperationService>();
Pamiętaj, że IOperationSingletonInstance
usługa korzysta z określonej instancji o znanym identyfikatorze Guid.Empty
, więc będzie jasne, kiedy ten typ jest używany. Zarejestrowaliśmy również opcję OperationService
zależną od każdego z pozostałych Operation
typów, dzięki czemu w żądaniu będzie jasne, czy ta usługa otrzymuje tę samą instancję, co kontroler, czy nową, dla każdego typu operacji. Wszystko, co robi ta usługa, ujawnia swoje zależności jako właściwości, dzięki czemu można je wyświetlać w widoku.
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;
}
}
}
Aby zademonstrować czasy życia obiektu w ramach oddzielnych indywidualnych żądań do aplikacji i pomiędzy nimi, próbka zawiera OperationsController
żądanie, które żąda każdego rodzaju, IOperation
jak również OperationService
. Następnie Index
akcja wyświetla wszystkie wartości kontrolera i usługi 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();
}
}
}
Teraz wysyłane są dwa osobne żądania do tej akcji kontrolera:
Obserwuj, które OperationId
wartości różnią się w obrębie żądania i między żądaniami.
Obiekty przejściowe są zawsze różne; nowa instancja jest dostarczana do każdego kontrolera i każdej usługi.
Obiekty o zasięgu są takie same w żądaniu, ale różne dla różnych żądań
Obiekty Singleton są takie same dla każdego obiektu i każdego żądania (niezależnie od tego, czy instancja jest dostarczona ConfigureServices
)