it-swarm.com.de

Unterschiede zwischen AddTransient, AddScoped und AddSingleton Services?

Ich möchte dependency injection in Asp.Net Core. Nachdem Sie diesen Code der ConfigureServices -Methode hinzugefügt haben, funktionieren beide Methoden.

Was ist der Unterschied zwischen services.AddTransient und service.AddScoped Methoden sind _Asp.Net Core_?

_public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddScoped<IEmailSender, AuthMessageSender>();
}
_
641
Elvin Mammadov

TL; DR

Transiente Objekte sind immer unterschiedlich. Für jede Steuerung und jeden Dienst wird eine neue Instanz bereitgestellt.

Objekte mit demselben Gültigkeitsbereich sind innerhalb einer Anforderung identisch, jedoch je nach Anforderung unterschiedlich.

Singleton-Objekte sind für jedes Objekt und jede Anforderung gleich.

Zur Verdeutlichung zeigt dieses Beispiel aus asp.net docs den Unterschied:

Stellen Sie sich eine einfache Schnittstelle vor, die eine oder mehrere Aufgaben als Operation mit der eindeutigen ID OperationId darstellt, um den Unterschied zwischen diesen Optionen für die Lebensdauer und für die Registrierung zu veranschaulichen. Abhängig davon, wie wir die Lebensdauer für diesen Service konfigurieren, stellt der Container der anfragenden Klasse dieselben oder unterschiedliche Instanzen des Service zur Verfügung. Um zu verdeutlichen, welche Lebensdauer angefordert wird, erstellen wir einen Typ pro Lebensdaueroption:

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 ein Guid in ihrem Konstruktor akzeptiert, oder verwenden ein neues Guid, wenn keines angegeben ist.

Als nächstes wird in ConfigureServices jeder Typ gemäß 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 Dienst IOperationSingletonInstance eine bestimmte Instanz mit der bekannten ID Guid.Empty verwendet, sodass klar ist, wann dieser Typ verwendet wird. Wir haben auch einen OperationService registriert, der von jedem der anderen Operation Typen abhängt, so dass innerhalb einer Anfrage klar wird, ob dieser Dienst die gleiche Instanz wie der Controller erhält oder eine neue, für jede Vorgangsart. Dieser Dienst macht lediglich seine Abhängigkeiten als Eigenschaften verfügbar, sodass 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 Lebensdauer des Objekts innerhalb und zwischen einzelnen Anforderungen an die Anwendung zu veranschaulichen, enthält das Beispiel einen OperationsController, der jede Art von IOperation-Typ anfordert, sowie einen OperationService. Die Aktion Index 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: First Request

Second Request

Beobachten Sie, welcher der OperationId Werte innerhalb einer Anfrage und zwischen den Anfragen variiert.

  • Transiente Objekte sind immer unterschiedlich. Für jede Steuerung und jeden Dienst wird eine neue Instanz bereitgestellt.

  • Objekte mit demselben Gültigkeitsbereich sind innerhalb einer Anforderung identisch, jedoch je nach Anforderung unterschiedlich

  • Singleton-Objekte sind für jedes Objekt und jede Anforderung gleich (unabhängig davon, ob eine Instanz in ConfigureServices bereitgestellt wird)

1168
akazemis

Bei der Dotnet-Abhängigkeitsinjektion gibt es drei Hauptlebensdauern:

Singleton , das eine einzelne Instanz in der gesamten Anwendung erstellt. Es erstellt die Instanz zum ersten Mal und verwendet dasselbe Objekt in allen Aufrufen erneut.

Gültigkeitsbereichsdienste werden einmal pro Anforderung innerhalb des Gültigkeitsbereichs erstellt. Es entspricht Singleton im aktuellen Bereich. z.B. In MVC wird pro http-Anforderung eine Instanz erstellt, in den anderen Aufrufen innerhalb derselben Webanforderung wird jedoch dieselbe Instanz verwendet.

Vorübergehende Lifetime-Services werden bei jeder Anforderung erstellt. Diese Lebensdauer ist am besten für leichte, zustandslose Dienste geeignet.

Hier finden Sie und Beispiele, um den Unterschied zu sehen:

http://dotnetliberty.com/index.php/2015/10/15/asp-net-5-mvc6-dependency-injection-in-6-steps/

https://codewala.net/2015/04/30/your-dependency-injection-ready-asp-net-asp-net-5/

und dies ist der Link zur offiziellen Dokumentation:

https://docs.asp.net/de/latest/fundamentals/dependency-injection.html#service-lifetimes-and-registration-options

270
akazemis
  • Singleton ist eine einzelne Instanz für die Lebensdauer der Anwendungsdomäne.
  • Bereich ist eine einzelne Instanz für die Dauer der Bereichsanforderung, dh pro HTTP Anforderung in ASP.NET.
  • Transient ist eine einzelne Instanz pro Code Anforderung.

Normalerweise sollte die Codeanforderung über einen Konstruktorparameter erfolgen, wie in

public MyConsumingClass(IDependency dependency)

Ich wollte in der Antwort von @ akazemis darauf hinweisen, dass "Services" im Kontext von DI nicht RESTful Services implizieren. Services sind Implementierungen von Abhängigkeiten, die Funktionalität bereitstellen.

24
user1969177

Transient, Scoped und Singleton definieren den Objekterstellungsprozess in ASP.NET MVC Core DI, wenn mehrere Objekte desselben Typs injiziert werden müssen. Falls Sie mit der Abhängigkeitsinjektion noch nicht vertraut sind, können Sie dies sehen DI IOC video

Sie können den folgenden Controller-Code sehen, in dem ich zwei Instanzen von "IDal" im Konstruktor angefordert habe. Transient, Scoped und Singleton definieren, ob dieselbe Instanz in "_dal" und "_dal1" oder anders injiziert wird.

public class CustomerController : Controller
    {
        IDal dal = null;
        public CustomerController(IDal _dal
                                ,IDal _dal1)
        {
            dal = _dal;
            // DI of MVC core
            // inversion of control
        }
}

Transient: - In transient werden neue Objektinstanzen in eine einzelne Anforderung und Antwort eingefügt. Unten ist ein Schnappschuss, in dem ich GUID Werte angezeigt habe.

enter image description here

Gültigkeitsbereich: - Im Gültigkeitsbereich wird dieselbe Objektinstanz in eine einzelne Anforderung und Antwort eingefügt.

enter image description here

Singleton: - In Singleton wird dasselbe Objekt in alle Anforderungen und Antworten eingefügt. In diesem Fall wird eine globale Instanz des Objekts erstellt.

Nachfolgend finden Sie ein einfaches Diagramm, in dem die obigen Grundlagen visuell erläutert werden.

MVC DI image

Das obige Bild wurde vom SBSS-Team gezeichnet, als ich ASP.NET MVC-Training in Mumbai Training absolvierte. Ein großes Dankeschön an das SBSS-Team für die Erstellung des obigen Bildes.

24

AddSingleton ()

AddSingleton () erstellt bei der ersten Anforderung eine einzelne Instanz des Dienstes und verwendet dieselbe Instanz an allen Stellen, an denen dieser Dienst benötigt wird.

AddScoped ()

Im Servicebereich erhalten wir bei jeder http-Anfrage eine neue Instanz. Wenn jedoch in derselben http-Anforderung der Dienst an mehreren Stellen wie in der Ansicht und im Controller erforderlich ist, wird dieselbe Instanz für den gesamten Umfang dieser http-Anforderung bereitgestellt. Bei jeder neuen http-Anforderung wird jedoch eine neue Instanz des Dienstes abgerufen.

AddTransient ()

Bei einem vorübergehenden Dienst wird jedes Mal eine neue Instanz bereitgestellt, wenn eine Dienstinstanz angefordert wird, unabhängig davon, ob sie sich im Bereich derselben http-Anforderung oder über verschiedene http-Anforderungen befindet.

3
Yasser

Nachdem ich nach einer Antwort auf diese Frage gesucht hatte, fand ich eine brillante Erklärung mit einem Beispiel, das ich mit Ihnen teilen möchte.

Sie können sich ein Video ansehen, das die Unterschiede zeigt HIER

In diesem Beispiel haben wir folgenden Code:

public interface IEmployeeRepository
{
    IEnumerable<Employee> GetAllEmployees();
    Employee Add(Employee employee);
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MockEmployeeRepository : IEmployeeRepository
{
    private List<Employee> _employeeList;

    public MockEmployeeRepository()
    {
        _employeeList = new List<Employee>()
    {
        new Employee() { Id = 1, Name = "Mary" },
        new Employee() { Id = 2, Name = "John" },
        new Employee() { Id = 3, Name = "Sam" },
    };
    }

    public Employee Add(Employee employee)
    {
        employee.Id = _employeeList.Max(e => e.Id) + 1;
        _employeeList.Add(employee);
        return employee;
    }

    public IEnumerable<Employee> GetAllEmployees()
    {
        return _employeeList;
    }
}

HomeController

public class HomeController : Controller
{
    private IEmployeeRepository _employeeRepository;

    public HomeController(IEmployeeRepository employeeRepository)
    {
        _employeeRepository = employeeRepository;
    }

    [HttpGet]
    public ViewResult Create()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Create(Employee employee)
    {
        if (ModelState.IsValid)
        {
            Employee newEmployee = _employeeRepository.Add(employee);
        }

        return View();
    }
}

Ansicht erstellen

@model Employee
@inject IEmployeeRepository empRepository

<form asp-controller="home" asp-action="create" method="post">
    <div>
        <label asp-for="Name"></label>
        <div>
            <input asp-for="Name">
        </div>
    </div>

    <div>
        <button type="submit">Create</button>
    </div>

    <div>
        Total Employees Count = @empRepository.GetAllEmployees().Count().ToString()
    </div>
</form>

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IEmployeeRepository, MockEmployeeRepository>();
}

Kopieren Sie den Code, fügen Sie ihn ein und klicken Sie in der Ansicht auf die Schaltfläche Erstellen. Sie können zwischen AddSingleton, AddScoped und AddTransient wechseln. Sie erhalten jedes Mal ein anderes Ergebnis, das Ihnen beim Verständnis dieser Erklärung helfen kann :

AddSingleton () - Wie der Name schon sagt, erstellt die AddSingleton () -Methode einen Singleton-Dienst. Ein Singleton-Dienst wird erstellt, wenn er zum ersten Mal angefordert wird. Dieselbe Instanz wird dann von allen nachfolgenden Anforderungen verwendet. Im Allgemeinen wird ein Singleton-Dienst nur einmal pro Anwendung erstellt und diese einzelne Instanz wird während der gesamten Lebensdauer der Anwendung verwendet.

AddTransient () - Diese Methode erstellt einen Transient-Dienst. Bei jeder Anforderung wird eine neue Instanz eines vorübergehenden Dienstes erstellt.

AddScoped () - Diese Methode erstellt einen Scoped-Service. Eine neue Instanz eines Bereichs-Service wird einmal pro Anforderung innerhalb des Bereichs erstellt. In einer Webanwendung wird beispielsweise pro http-Anforderung eine Instanz erstellt, in den anderen Aufrufen innerhalb derselben Webanforderung wird jedoch dieselbe Instanz verwendet.

2
Offir Pe'er

Wie beschrieben hier (dieser Link ist sehr nützlich) mit einem Beispiel,

Diese Zuordnung zwischen der Schnittstelle und dem konkreten Typ definiert, dass Sie bei jeder Anforderung eines IContryService-Typs eine neue Instanz des CountryService erhalten. Das bedeutet in diesem Fall vorübergehend. Sie können auch Singleton-Zuordnungen (mit AddSingleton) und Bereichszuordnungen (mit AddScoped) hinzufügen. Gültigkeitsbereich bedeutet in diesem Fall Gültigkeitsbereich für eine HTTP-Anforderung. Dies bedeutet auch, dass es sich um einen Singleton handelt, während die aktuelle Anforderung ausgeführt wird. Sie können dem DI-Container auch eine vorhandene Instanz mit der Methode AddInstance hinzufügen. Dies sind die fast vollständigen Möglichkeiten, sich bei der IServiceCollection zu registrieren

1
Rehmanali Momin