TL; DR
Vorübergehende Objekte sind immer unterschiedlich. Jeder Steuerung und jedem Dienst wird eine neue Instanz bereitgestellt.
Objekte mit Gültigkeitsbereich sind innerhalb einer Anforderung gleich, unterscheiden sich jedoch in verschiedenen Anforderungen.
Singleton-Objekte sind für jedes Objekt und jede Anforderung gleich.
Zur Verdeutlichung zeigt dieses Beispiel aus der ASP.NET-Dokumentation den Unterschied:
Um den Unterschied zwischen diesen Lebensdauer- und Registrierungsoptionen zu demonstrieren, betrachten Sie eine einfache Schnittstelle, die eine oder mehrere Aufgaben als Vorgang mit einer eindeutigen Kennung darstellt OperationId
. Abhängig davon, wie wir die Lebensdauer für diesen Dienst konfigurieren, stellt der Container der anfordernden Klasse entweder die gleichen oder verschiedene Instanzen des Dienstes zur Verfügung. Um zu verdeutlichen, welche Lebensdauer angefordert wird, erstellen wir einen Typ pro Lebenszeitoption:
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
{
}
}
Wir implementieren diese Schnittstellen mit einer einzelnen Klasse, Operation
die eine GUID in ihrem Konstruktor akzeptiert, oder verwenden eine neue GUID, wenn keine angegeben ist:
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;
}
}
Als Nächstes wird ConfigureServices
jeder Typ entsprechend seiner benannten Lebensdauer zum Container hinzugefügt:
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
services.AddTransient<OperationService, OperationService>();
Beachten Sie, dass der IOperationSingletonInstance
Dienst eine bestimmte Instanz mit einer bekannten ID von verwendet Guid.Empty
, sodass klar ist, wann dieser Typ verwendet wird. Wir haben auch eine registriert OperationService
, die von jedem der anderen Operation
Typen abhängt , sodass innerhalb einer Anfrage klar wird, ob dieser Dienst für jeden Operationstyp dieselbe oder eine neue Instanz wie der Controller erhält. Dieser Dienst macht lediglich seine Abhängigkeiten als Eigenschaften verfügbar, damit sie in der Ansicht angezeigt werden können.
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;
}
}
}
Um die Objektlebensdauer innerhalb und zwischen einzelnen Anforderungen an die Anwendung zu demonstrieren, enthält das Beispiel eine OperationsController
, die jede Art von IOperation
Typ anfordert, sowie eine OperationService
. Die Index
Aktion zeigt dann alle OperationId
Werte des Controllers und des Dienstes an .
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();
}
}
}
Nun werden zwei separate Anforderungen an diese Controller-Aktion gestellt:
Beobachten Sie, welcher der OperationId
Werte innerhalb einer Anforderung und zwischen Anforderungen variiert.
Vorübergehende Objekte sind immer unterschiedlich. Jeder Steuerung und jedem Dienst wird eine neue Instanz bereitgestellt.
Objekte mit Gültigkeitsbereich sind innerhalb einer Anforderung gleich, unterscheiden sich jedoch in verschiedenen Anforderungen
Singleton-Objekte sind für jedes Objekt und jede Anforderung gleich (unabhängig davon, ob eine Instanz in bereitgestellt wird ConfigureServices
).