TL; DR
Los objetos transitorios son siempre diferentes; Se proporciona una nueva instancia para cada controlador y cada servicio.
Los objetos de ámbito son los mismos dentro de una solicitud, pero diferentes en diferentes solicitudes.
Los objetos Singleton son los mismos para cada objeto y cada solicitud.
Para más aclaraciones, este ejemplo de la documentación de ASP.NET muestra la diferencia:
Para demostrar la diferencia entre estas opciones de vida y de registro, considere una interfaz simple que representa una o más tareas como una operación con un identificador único, OperationId
. Dependiendo de cómo configuremos la vida útil de este servicio, el contenedor proporcionará la misma o diferentes instancias del servicio a la clase solicitante. Para dejar en claro qué duración se solicita, crearemos una opción de tipo por duración:
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
{
}
}
Implementamos estas interfaces usando una sola clase, Operation
que acepta un GUID en su constructor, o usa un nuevo GUID si no se proporciona ninguno:
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;
}
}
A continuación, en ConfigureServices
, cada tipo se agrega al contenedor de acuerdo con su vida útil nombrada:
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
services.AddTransient<OperationService, OperationService>();
Tenga en cuenta que el IOperationSingletonInstance
servicio está utilizando una instancia específica con un ID conocido de Guid.Empty
, por lo que quedará claro cuando este tipo esté en uso. También hemos registrado uno OperationService
que depende de cada uno de los otros Operation
tipos, de modo que quede claro dentro de una solicitud si este servicio está obteniendo la misma instancia que el controlador, o una nueva, para cada tipo de operación. Todo lo que hace este servicio es exponer sus dependencias como propiedades, para que puedan mostrarse en la 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;
}
}
}
Para demostrar las vidas de los objetos dentro y entre solicitudes individuales separadas a la aplicación, la muestra incluye un OperationsController
que solicita cada tipo de IOperation
tipo, así como un OperationService
. La Index
acción luego muestra todos los OperationId
valores del controlador y del servicio .
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();
}
}
}
Ahora se realizan dos solicitudes separadas para esta acción del controlador:
Observe cuál de los OperationId
valores varía dentro de una solicitud y entre solicitudes.
Los objetos transitorios son siempre diferentes; Se proporciona una nueva instancia para cada controlador y cada servicio.
Los objetos de ámbito son los mismos dentro de una solicitud, pero diferentes en diferentes solicitudes
Los objetos Singleton son los mismos para cada objeto y cada solicitud (independientemente de si se proporciona una instancia ConfigureServices
)