TL; DR
Gli oggetti transitori sono sempre diversi; viene fornita una nuova istanza per ogni controller e ogni servizio.
Gli oggetti con ambito sono gli stessi all'interno di una richiesta, ma diversi tra richieste diverse.
Gli oggetti Singleton sono gli stessi per ogni oggetto e ogni richiesta.
Per ulteriori chiarimenti, questo esempio dalla documentazione ASP.NET mostra la differenza:
Per dimostrare la differenza tra queste opzioni di durata e di registrazione, prendere in considerazione una semplice interfaccia che rappresenta una o più attività come un'operazione con un identificatore univoco, OperationId
. A seconda di come configuriamo la durata di questo servizio, il contenitore fornirà alla classe richiedente la stessa o diverse istanze del servizio. Per chiarire quale durata viene richiesta, creeremo un tipo per opzione di durata:
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
{
}
}
Implementiamo queste interfacce utilizzando una singola classe, Operation
che accetta un GUID nel suo costruttore o utilizza un nuovo GUID se non ne viene fornito nessuno:
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;
}
}
Successivamente, in ConfigureServices
, ogni tipo viene aggiunto al contenitore in base alla sua durata:
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
services.AddTransient<OperationService, OperationService>();
Si noti che il IOperationSingletonInstance
servizio utilizza un'istanza specifica con un ID noto di Guid.Empty
, quindi sarà chiaro quando questo tipo è in uso. Abbiamo anche registrato un OperationService
parametro che dipende da ciascuno degli altri Operation
tipi, in modo che all'interno di una richiesta sia chiaro se questo servizio sta ottenendo la stessa istanza del controller o una nuova per ciascun tipo di operazione. Tutto questo servizio non fa altro che esporre le sue dipendenze come proprietà, in modo che possano essere visualizzate nella vista.
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;
}
}
}
Per dimostrare la durata dell'oggetto all'interno e tra singole richieste separate per l'applicazione, l'esempio include un OperationsController
che richiede ogni tipo di IOperation
tipo e un OperationService
. L' Index
azione visualizza quindi tutti i OperationId
valori del controller e del servizio .
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();
}
}
}
Ora vengono fatte due richieste separate per questa azione del controller:
Osservare quale dei OperationId
valori varia all'interno di una richiesta e tra le richieste.
Gli oggetti transitori sono sempre diversi; viene fornita una nuova istanza per ogni controller e ogni servizio.
Gli oggetti con ambito sono gli stessi all'interno di una richiesta, ma diversi tra richieste diverse
Gli oggetti Singleton sono gli stessi per ogni oggetto e ogni richiesta (indipendentemente dal fatto che sia fornita un'istanza ConfigureServices
)