Различия в службах AddTransient, AddScoped и AddSingleton?

Я хочу реализовать dependency injection в Asp.Net Core. Поэтому после добавления этих кодов в метод ConfigureServices оба способа работают.

В чем разница между методами services.AddTransient и service.AddScoped в Asp.Net Core?

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

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

Ответ 1

TL; DR

Временные объекты всегда разные; новый экземпляр предоставляется каждый контроллер и каждый сервис.

Объекты области видимости одинаковы в запросе, но различаются разные запросы.

Объекты Singleton одинаковы для каждого объекта и каждого запроса.

Для большей ясности, в этом примере из документов asp.net показано различие:

Чтобы продемонстрировать разницу между этими параметрами времени жизни и регистрации, рассмотрим простой интерфейс, который представляет одну или несколько задач как операцию с уникальным идентификатором OperationId. В зависимости от того, как мы настроим время жизни для этой службы, контейнер предоставит запрашивающему классу либо одинаковые, либо разные экземпляры службы. Чтобы было понятно, какое время жизни запрашивается, мы создадим один тип на время жизни:

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
    {
    }
}

Мы реализуем эти интерфейсы, используя один класс, Operation, который принимает Guid в своем конструкторе, или использует новый Guid, если ни один не указан:

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;
    }
}

Затем в ConfigureServices каждый тип добавляется в контейнер в соответствии с его именованным временем жизни:

services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
services.AddTransient<OperationService, OperationService>();

Обратите внимание, что служба IOperationSingletonInstance использует конкретный экземпляр с известным идентификатором Guid.Empty, поэтому будет ясно, когда этот тип используется. Мы также зарегистрировали OperationService, который зависит от каждого из других типов Operation, так что в запросе будет ясно, получает ли эта служба тот же экземпляр, что и контроллер, или новый, для каждого типа операции., Все, что делает этот сервис, представляет его зависимости как свойства, чтобы они могли отображаться в представлении.

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;
        }
    }
}

Чтобы продемонстрировать время жизни объекта внутри и между отдельными отдельными запросами к приложению, образец включает в себя OperationsController, который запрашивает каждый тип типа IOperation, а также OperationService. Затем действие Index отображает все значения контроллеров и служб 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();
        }
    }
}

Теперь к этому действию контроллера сделаны два отдельных запроса: First Request

Second Request

Обратите внимание, какое из значений OperationId варьируется в запросе и между запросами.

  • Временные объекты всегда разные; новый экземпляр предоставляется каждому контроллеру и каждой службе.

  • Объекты в одной области одинаковы в запросе, но различаются в разных запросах

  • Объекты Singleton одинаковы для каждого объекта и каждого запроса (независимо от того, предоставлен ли экземпляр в ConfigureServices)

Ответ 2

В инъекции зависимостей dotnet имеется 3 основных срока службы:

Singleton, который создает один экземпляр во всем приложении. Он создает экземпляр в первый раз и повторно использует один и тот же объект во всех вызовах.

Облачные службы времени жизни создаются один раз для каждого запроса в пределах области действия. Это эквивалентно Singleton в текущей области. например. в MVC он создает 1 экземпляр для каждого HTTP-запроса, но использует один и тот же экземпляр в других вызовах внутри одного и того же веб-запроса.

Временные службы времени жизни создаются каждый раз, когда они запрашиваются. Эта жизнь лучше всего работает для облегченных, безгосударственных услуг.

Здесь вы можете найти и примеры, чтобы увидеть разницу:

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/

и это ссылка на официальную документацию:

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

Ответ 3

  • Singleton - это единственный экземпляр для срока службы приложения домен.
  • Область видимости - это единственный экземпляр на протяжении всего диапазона запрос, что означает каждый HTTP-запрос в ASP.NET.
  • Transient - это один экземпляр для запроса кода.

Обычно запрос кода должен выполняться через параметр конструктора, как в

public MyConsumingClass(IDependency dependency)

Я хотел указать в @akazemis, что "услуги" в контексте DI не подразумевают услуги RESTful; услуги - это реализации зависимостей, которые обеспечивают функциональность.

Ответ 4

Transient, scoped и singleton определяют процесс создания объекта в ядре ASP.NET MVC core, когда нужно вводить несколько объектов одного типа. Если вы новичок в инъекции зависимостей, вы можете увидеть это видео DI IOC

Вы можете увидеть приведенный ниже код контроллера, в котором я запросил два экземпляра "IDal" в конструкторе. Transient, Scoped и Singleton определяют, будет ли тот же самый экземпляр введен в "_dal" и "_dal1" или другой.

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

Transient: - В переходных экземплярах новых объектов будут введены в один запрос и ответ. Ниже приведено изображение моментального снимка, в котором отображаются значения GUID.

введите описание изображения здесь

Область действия: - В области с одинаковыми объектами экземпляр будет инъецирован в один запрос и ответ.

введите описание изображения здесь

Синглтон: - В Singleton один и тот же объект будет вводиться через весь запрос и ответ. В этом случае будет создан один глобальный экземпляр объекта.

Ниже приведена простая диаграмма, которая объясняет это в основном визуально.

MVC DI image

Вышеприведенное изображение было составлено командой SBSS, когда я принимал обучение ASP.NET MVC в Мумбае, большое спасибо команде SBSS, чтобы создайте изображение выше.

Ответ 5

AddSingleton()

AddSingleton() создает один экземпляр службы при первом запросе и повторно использует этот же экземпляр во всех местах, где требуется эта служба.

AddScoped()

В области обслуживания с каждым запросом http мы получаем новый экземпляр. Однако если в одном и том же запросе http служба требуется в нескольких местах, например, в представлении и в контроллере, то для всего объема этого запроса http предоставляется один и тот же экземпляр. Но каждый новый http-запрос будет получать новый экземпляр службы.

AddTransient()

В случае временной службы новый экземпляр предоставляется каждый раз, когда запрашивается экземпляр службы, находится ли он в пределах одного и того же http-запроса или в разных HTTP-запросах.

Ответ 6

После поиска ответа на этот вопрос я нашел блестящее объяснение с примером, которым я хотел бы поделиться с вами.

Вы можете посмотреть видео, демонстрирующее различия ЗДЕСЬ

В этом примере у нас есть этот код:

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();
    }
}

Создать вид

@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>();
}

Скопируйте и вставьте этот код, нажмите кнопку "Создать" в представлении и переключайтесь между AddSingleton, AddScoped и AddTransient вы будете каждый раз получать разные результаты, которые могут помочь вам понять это объяснение:

AddSingleton() - Как видно из названия, метод AddSingleton() создает Синглтон сервис. Сервис Singleton создается, когда он первый просил. Этот же экземпляр затем используется всеми последующими Запросы. Так что в общем случае сервис Singleton создается только один раз за приложение, и этот единственный экземпляр используется на протяжении время жизни приложения.

AddTransient() - этот метод создает временный сервис. Новый Экземпляр временной службы создается каждый раз, когда она запрашивается.

AddScoped() - этот метод создает службу Scoped. Новый экземпляр служба Scoped создается один раз для каждого запроса в области. За Например, в веб-приложении создается 1 экземпляр для каждого http запрос, но использует тот же экземпляр в других вызовах в том же веб-запрос.

Ответ 7

Как описано здесь (эта ссылка очень полезна) с примером,

Это отображение между интерфейсом и конкретным типом определяет, что каждый раз, когда вы запрашиваете тип IContryService, вы получаете новый экземпляр CountryService. Вот что означает переходный процесс в этом случае. Вы также можете добавлять одноэлементные сопоставления (используя AddSingleton) и сопоставления областей (используя AddScoped). Область действия в этом случае означает область действия для HTTP-запроса, что также означает, что он является одноэлементным во время выполнения текущего запроса. Вы также можете добавить существующий экземпляр в контейнер DI, используя метод AddInstance. Это почти полные способы регистрации на IServiceCollection.

Ответ 8

Что означает Синглтон? Singleton - это класс, который позволяет создавать только один его экземпляр и предоставляет доступ к этому созданному экземпляру. Он содержит статические переменные, которые могут содержать уникальные и частные экземпляры самого себя. Он используется в сценариях, когда пользователь хочет ограничить создание экземпляра класса только одним объектом. Обычно это полезно, когда для координации действий в системе требуется один объект. Шаблон singleton используется в языках программирования, таких как Java и .NET, для определения глобальной переменной. Один объект, используемый в системах, остается постоянным и должен быть определен только один раз, а не много раз.