[.NET, ASP, C#] Разница между AddTransient, AddScoped и AddSingleton в ASP.NET Core (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
ВведениеПонимание жизненного цикла внедряемых зависимостей в приложениях ASP.Net Core очень важно. Как мы знаем, внедрение зависимостей (DI - Dependency Injection) - это метод достижения слабой связанности между объектами и их коллабораторами, или зависимостями. Чаще всего классы объявляют свои зависимости через конструктор, в рамках реализации принципа явных зависимостей (Explicit Dependencies Principle). Этот подход известен как «constructor injection». Чтобы реализовать внедрение зависимостей, нам нужно настроить DI-контейнер с классами, которые участвуют во внедрении зависимостей. DI-контейнер должен решать, возвращать ли новый инстанс сервиса или предоставить уже существующий. Мы выполняем это действие с помощью метода ConfigureServices в классе startup. Жизненный цикл сервиса зависит от того, когда создается инстанс зависимости и как долго он существует, а также от того, как мы зарегистрировали этот сервис. Жизненный цикл сервиса определяют следующие три метода:
- AddTransient
Transient подразумевает, что сервис создается каждый раз, когда его запрашивают. Этот жизненный цикл лучше всего подходит для легковесных, не фиксирующих состояние, сервисов.
- AddScoped
Scoped - сервис создаются единожды для каждого запроса.
- AddSingleton
Singleton - сервис создается при первом запросе (или при запуске ConfigureServices, если вы указываете инстанс там), а затем каждый последующий запрос будет использовать этот же инстанс.
Жизненные циклы внедренных зависимостей на примере Давайте разберемся с жизненными циклами внедренных зависисмостей на примере ASP.NET Core приложения.
В своем примере я создал три интерфейса с именами ItransientService, IScopedService и ISingletonService - по одному на каждый из типов жизненных циклов внедренных зависимостей. Все эти интерфейсы содержат один единственный метод, именуемый GetOperationID(), который возвращает уникальный Guid.
using System;
namespace TransientScopedSingleton {
publicinterfaceITransientService {
Guid GetOperationID();
}
}
using System;
namespace TransientScopedSingleton {
publicinterfaceIScopedService {
Guid GetOperationID();
}
}
using System;
namespace TransientScopedSingleton {
publicinterfaceISingletonService {
Guid GetOperationID();
}
}
Давайте реализуем эти три интерфейса в сервисе OperationService.
using System;
namespace TransientScopedSingleton {
publicclassOperationService: ITransientService,
IScopedService,
ISingletonService {
Guid id;
publicOperationService() {
id = Guid.NewGuid();
}
public Guid GetOperationID() {
return id;
}
}
}
Теперь зарегистрируем OperationService через эти три интерфейса, как показано ниже, в методе ConfigureServices класса startup.
services.AddTransient<ITransientService, OperationService>();
services.AddScoped<IScopedService, OperationService>();
services.AddSingleton<ISingletonService, OperationService>();
Потрясающе! Теперь мы готовы внедрить эти сервисы в контроллер. Для большей наглядности мы внедрим по два экземпляра каждого сервиса через конструктор HomeController.
private readonly ILogger<HomeController> _logger;
private readonly ITransientService _transientService1;
private readonly ITransientService _transientService2;
private readonly IScopedService _scopedService1;
private readonly IScopedService _scopedService2;
private readonly ISingletonService _singletonService1;
private readonly ISingletonService _singletonService2;
public HomeController(ILogger<HomeController> logger,
ITransientService transientService1,
ITransientService transientService2,
IScopedService scopedService1,
IScopedService scopedService2,
ISingletonService singletonService1,
ISingletonService singletonService2)
{
_logger = logger;
_transientService1 = transientService1;
_transientService2 = transientService2;
_scopedService1 = scopedService1;
_scopedService2 = scopedService2;
_singletonService1 = singletonService1;
_singletonService2 = singletonService2;
}
Теперь мы вызовем метод GetOperationID инстанса каждого сервиса и назначим его viewbag, чтобы мы могли наблюдать эти значения в пользовательском интерфейсе.
public IActionResult Index()
{
ViewBag.transient1 = _transientService1.GetOperationID().ToString();
ViewBag.transient2 = _transientService2.GetOperationID().ToString();
ViewBag.scoped1 = _scopedService1.GetOperationID().ToString();
ViewBag.scoped2 = _scopedService2.GetOperationID().ToString();
ViewBag.singleton1 = _singletonService1.GetOperationID().ToString();
ViewBag.singleton2 = _singletonService2.GetOperationID().ToString();
return View();
}
Изменим представление для отображения идентификаторов соответствующих типов сервисов.
<div class="text-center">
<h2 class="display-4">Dependency Injection Lifetime
</h2>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>Service Type</th>
<th>First Instance Operation ID</th>
<th>Second Instance Operation ID</th>
</tr>
</thead>
<tbody>
<tr>
<tdstyle="background-color: darksalmon">Transient
</td>
<tdstyle="background-color: darksalmon">@ViewBag.transient1
</td>
<tdstyle="background-color: darksalmon">@ViewBag.transient2
</td>
</tr>
<tr>
<td>Scoped</td>
<td>@ViewBag.scoped1</td>
<td>@ViewBag.scoped2</td>
</tr>
<tr>
<tdstyle="background-color: aquamarine">Singleton
</td>
<tdstyle="background-color: aquamarine">@ViewBag.singleton1
</td>
<tdstyle="background-color: aquamarine">@ViewBag.singleton2
</td>
</tr>
</tbody>
</table>
После того, как мы запустим приложение, мы увидим, что для соответствующих типов сервисов отображаются два отдельных Guid. Теперь запустим два инстанса пользовательского интерфейса в двух разных вкладках браузера, чтобы можно было отправить два независимых запроса. Запрос 1
Запрос 2
НаблюденияTransient-сервис всегда возвращает новый инстанс, даже в рамках одного и того же запроса, поэтому идентификаторы операций для первого и второго инстанса различаются у обоих запросов (Запрос 1 и Запрос 2). В случае Scoped-сервиса на каждый запрос создается по одному инстансу, который затем используется в рамках всего запроса. Вот почему идентификаторы операций одинаковы для первого и второго инстанса Запроса 1. Но если мы обновим страницу или загрузим пользовательский интерфейс в другой вкладке браузера (что представляет собой не что иное, как Запрос 2), мы увидим новый идентификатор. В случае Singleton-сервиса создается только один инстанс, который совместно используется всеми компонентами приложениями. Если мы обновим страницу или загрузим пользовательский интерфейс на другой вкладке браузера (опять же Запрос 2), мы увидим те же идентификаторы. Service Тип сервисаВ рамках одного http-запросаДля двух разных http-запросовTransientНовый инстансНовый инстансScopedУже существующий инстансНовый инстансSingletonУже существующий инстансУже существующий инстанс ЗаключениеДавайте подытожим то, что мы с вами обсудили.
- Для transient-сервиса предоставляется новый инстанс каждый раз, когда он запрашивается, независимо от того, происходит ли это в рамках одного и того же HTTP-запроса или в разных.
- Для scoped-сервиса мы получаем один и тот же инстанс в рамках одного HTTP-запроса, и разные для разных HTTP-запросов.
- Singleton-служба предполагает только один инстанс. Инстанс создается при первом запросе сервиса, и этот единственный инстанс будет использоваться для всех последующих HTTP-запросов во всем приложении.
Спасибо за внимание!
Прямо сейчас в OTUS открыт набор на новый поток курса "C# ASP.NET Core разработчик". Всех желающих приглашаем записаться на demo day курса, в рамках которого вы сможете подробно узнать о программе обучения, а также задать преподавателям вопросы, которые вас интересуют.
===========
Источник:
habr.com
===========
===========
Автор оригинала: Anupam Maiti
===========Похожие новости:
- [Тестирование IT-систем, Программирование, Java, Тестирование веб-сервисов] AspectJ в автоматическом тестировании — несколько практических примеров
- [Информационная безопасность, Разработка веб-сайтов, Анализ и проектирование систем, .NET] RBAC? ABAC?.. PERM! Новый подход к авторизации в облачных веб-службах и приложениях
- [Управление проектами, Бизнес-модели] BPMN простым языком
- [Программирование, C, Карьера в IT-индустрии] Для чего идут изучать язык С?
- [.NET, Разработка мобильных приложений, Сетевые технологии, C#, История IT] Менеджер приложений для Windows Mobile
- [Программирование, C#, Учебный процесс в IT] Как избавиться от if-else при помощи команд и обработчиков (перевод)
- [Настройка Linux, Сетевые технологии] Сокеты в ОС Linux
- [Программирование, .NET, C#] Провайдер логирования для Telegram (.NET 5 / .NET Core)
- [.NET, Облачные сервисы] Переход с Azure на GCP, с ASP.NET MVC на ASP.NET Core 3.1
- [Программирование, Java, Микросервисы] Spring Cloud и Spring Boot. Часть 1: использование Eureka Server (перевод)
Теги для поиска: #_.net, #_asp, #_c#, #_addtransient, #_addscoped, #_addsingleton, #_asp, #_.net, #_blog_kompanii_otus._onlajnobrazovanie (
Блог компании OTUS. Онлайн-образование
), #_.net, #_asp, #_c#
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:56
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
ВведениеПонимание жизненного цикла внедряемых зависимостей в приложениях ASP.Net Core очень важно. Как мы знаем, внедрение зависимостей (DI - Dependency Injection) - это метод достижения слабой связанности между объектами и их коллабораторами, или зависимостями. Чаще всего классы объявляют свои зависимости через конструктор, в рамках реализации принципа явных зависимостей (Explicit Dependencies Principle). Этот подход известен как «constructor injection». Чтобы реализовать внедрение зависимостей, нам нужно настроить DI-контейнер с классами, которые участвуют во внедрении зависимостей. DI-контейнер должен решать, возвращать ли новый инстанс сервиса или предоставить уже существующий. Мы выполняем это действие с помощью метода ConfigureServices в классе startup. Жизненный цикл сервиса зависит от того, когда создается инстанс зависимости и как долго он существует, а также от того, как мы зарегистрировали этот сервис. Жизненный цикл сервиса определяют следующие три метода:
В своем примере я создал три интерфейса с именами ItransientService, IScopedService и ISingletonService - по одному на каждый из типов жизненных циклов внедренных зависимостей. Все эти интерфейсы содержат один единственный метод, именуемый GetOperationID(), который возвращает уникальный Guid. using System;
namespace TransientScopedSingleton { publicinterfaceITransientService { Guid GetOperationID(); } } using System; namespace TransientScopedSingleton { publicinterfaceIScopedService { Guid GetOperationID(); } } using System; namespace TransientScopedSingleton { publicinterfaceISingletonService { Guid GetOperationID(); } } using System;
namespace TransientScopedSingleton { publicclassOperationService: ITransientService, IScopedService, ISingletonService { Guid id; publicOperationService() { id = Guid.NewGuid(); } public Guid GetOperationID() { return id; } } } services.AddTransient<ITransientService, OperationService>();
services.AddScoped<IScopedService, OperationService>(); services.AddSingleton<ISingletonService, OperationService>(); private readonly ILogger<HomeController> _logger;
private readonly ITransientService _transientService1; private readonly ITransientService _transientService2; private readonly IScopedService _scopedService1; private readonly IScopedService _scopedService2; private readonly ISingletonService _singletonService1; private readonly ISingletonService _singletonService2; public HomeController(ILogger<HomeController> logger, ITransientService transientService1, ITransientService transientService2, IScopedService scopedService1, IScopedService scopedService2, ISingletonService singletonService1, ISingletonService singletonService2) { _logger = logger; _transientService1 = transientService1; _transientService2 = transientService2; _scopedService1 = scopedService1; _scopedService2 = scopedService2; _singletonService1 = singletonService1; _singletonService2 = singletonService2; } public IActionResult Index()
{ ViewBag.transient1 = _transientService1.GetOperationID().ToString(); ViewBag.transient2 = _transientService2.GetOperationID().ToString(); ViewBag.scoped1 = _scopedService1.GetOperationID().ToString(); ViewBag.scoped2 = _scopedService2.GetOperationID().ToString(); ViewBag.singleton1 = _singletonService1.GetOperationID().ToString(); ViewBag.singleton2 = _singletonService2.GetOperationID().ToString(); return View(); } <div class="text-center">
<h2 class="display-4">Dependency Injection Lifetime </h2> </div> <table class="table table-bordered"> <thead> <tr> <th>Service Type</th> <th>First Instance Operation ID</th> <th>Second Instance Operation ID</th> </tr> </thead> <tbody> <tr> <tdstyle="background-color: darksalmon">Transient </td> <tdstyle="background-color: darksalmon">@ViewBag.transient1 </td> <tdstyle="background-color: darksalmon">@ViewBag.transient2 </td> </tr> <tr> <td>Scoped</td> <td>@ViewBag.scoped1</td> <td>@ViewBag.scoped2</td> </tr> <tr> <tdstyle="background-color: aquamarine">Singleton </td> <tdstyle="background-color: aquamarine">@ViewBag.singleton1 </td> <tdstyle="background-color: aquamarine">@ViewBag.singleton2 </td> </tr> </tbody> </table> Запрос 2 НаблюденияTransient-сервис всегда возвращает новый инстанс, даже в рамках одного и того же запроса, поэтому идентификаторы операций для первого и второго инстанса различаются у обоих запросов (Запрос 1 и Запрос 2). В случае Scoped-сервиса на каждый запрос создается по одному инстансу, который затем используется в рамках всего запроса. Вот почему идентификаторы операций одинаковы для первого и второго инстанса Запроса 1. Но если мы обновим страницу или загрузим пользовательский интерфейс в другой вкладке браузера (что представляет собой не что иное, как Запрос 2), мы увидим новый идентификатор. В случае Singleton-сервиса создается только один инстанс, который совместно используется всеми компонентами приложениями. Если мы обновим страницу или загрузим пользовательский интерфейс на другой вкладке браузера (опять же Запрос 2), мы увидим те же идентификаторы. Service Тип сервисаВ рамках одного http-запросаДля двух разных http-запросовTransientНовый инстансНовый инстансScopedУже существующий инстансНовый инстансSingletonУже существующий инстансУже существующий инстанс ЗаключениеДавайте подытожим то, что мы с вами обсудили.
Прямо сейчас в OTUS открыт набор на новый поток курса "C# ASP.NET Core разработчик". Всех желающих приглашаем записаться на demo day курса, в рамках которого вы сможете подробно узнать о программе обучения, а также задать преподавателям вопросы, которые вас интересуют.
=========== Источник: habr.com =========== =========== Автор оригинала: Anupam Maiti ===========Похожие новости:
Блог компании OTUS. Онлайн-образование ), #_.net, #_asp, #_c# |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:56
Часовой пояс: UTC + 5