← Назад к вопросам
В чём разница между Transient, Scoped и Singleton?
1.2 Junior🔥 272 комментариев
#Dependency Injection и IoC#Основы C# и .NET
Комментарии (2)
🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В чём разница между Transient, Scoped и Singleton в ASP.NET Core DI?
В ASP.NET Core Dependency Injection (DI) существует три основных времени жизни (lifetime) служб: Transient, Scoped и Singleton. Понимание этих различий критично для корректного управления ресурсами, состояниями и многопоточностью в веб-приложениях.
Основные различия по времени жизни
1. Transient (Мгновенная)
- Создание: Новый экземпляр создаётся каждый раз при запросе службы из контейнера зависимостей.
- Область видимости: Кратковременная, существует только в рамках одного запроса на инъекцию.
- Использование: Идеально для лёгких, не имеющих состояния (stateless) служб, где каждый вызов должен быть изолирован.
// Регистрация
services.AddTransient<IMyService, MyService>();
// Использование: каждый раз новый экземпляр
// В контроллере:
public class HomeController : Controller
{
private readonly IMyService _service1;
private readonly IMyService _service2;
public HomeController(IMyService service1, IMyService service2)
{
// service1 и service2 - РАЗНЫЕ экземпляры
_service1 = service1;
_service2 = service2;
}
}
2. Scoped (Область видимости)
- Создание: Один экземпляр создаётся на область видимости (scope). В веб-приложении область видимости обычно соответствует одному HTTP-запросу.
- Область видимости: Экземпляр живёт в рамках одной области (scope) и уничтожается при её завершении.
- Использование: Подходит для служб, которым необходимо сохранять состояние в рамках одного запроса, например для DbContext в Entity Framework Core.
// Регистрация
services.AddScoped<IMyDbContext, MyDbContext>();
// Использование: один экземпляр на запрос
// В рамках одного HTTP-запроса все инъекции получат один и тот же экземпляр
public class OrderService : IOrderService
{
private readonly IMyDbContext _dbContext;
// В рамках одного запроса все сервисы получат одинаковый DbContext
}
3. Singleton (Одиночка)
- Создание: Единственный экземпляр создаётся при первом запросе и существует на протяжении всего жизненного цикла приложения.
- Область видимости: Глобальная, существует до остановки приложения.
- Использование: Для глобальных, общих ресурсов, кешей, конфигураций, которые должны быть доступны всем запросам.
// Регистрация
services.AddSingleton<ICacheService, CacheService>();
// Использование: один экземпляр на всё приложение
// Этот экземпляр будет использоваться всеми запросами одновременно
Практические примеры и рекомендации
Безопасность потоков (Thread Safety)
- Singleton службы должны быть потокобезопасными, так как к ним обращаются одновременно из множества потоков.
- Scoped службы обычно не требуют полной потокобезопасности, так как один экземпляр используется только в рамках одного запроса.
- Transient службы обычно не требуют потокобезопасности, если не используются в многопоточных сценариях.
Типичные сценарии использования
- Transient: Сервисы для вычислений, валидаторы, мапперы (AutoMapper), простые фабрики
- Scoped: Entity Framework Core DbContext, репозитории, сервисы бизнес-логики
- Singleton: Кеши, клиенты для внешних API (если потокобезопасны), конфигурации, логгеры
Важные предупреждения и антипаттерны
// ОПАСНО: Singleton зависит от Scoped службы
services.AddSingleton<ISingletonService>(provider =>
{
var scopedService = provider.GetRequiredService<IScopedService>();
// Это вызовет проблему, так как Scoped служба будет "заперта" в Singleton
return new SingletonService(scopedService);
});
// Решение: использовать фабрики или изменить время жизни
Производительность и управление ресурсами
- Singleton наиболее эффективен по памяти и времени создания, но требует тщательного управления состоянием.
- Transient может создавать нагрузку при частом создании тяжёлых объектов.
- Scoped представляет баланс между изоляцией и производительностью для веб-приложений.
Визуализация различий
HTTP Запрос 1: [Transient A, Transient B] [Scoped X] [Singleton 1]
HTTP Запрос 2: [Transient C, Transient D] [Scoped Y] [Singleton 1]
HTTP Запрос 3: [Transient E, Transient F] [Scoped Z] [Singleton 1]
Выбор правильного времени жизни — это компромисс между изоляцией данных, производительностью и управлением памятью. Неправильный выбор может привести к утечкам памяти, проблемам с параллелизмом или непредсказуемому поведению приложения.