0Pricing
C# Academy · Урок

Время жизни служб: Transient, Scoped, Singleton

Узнайте, как время жизни Transient, Scoped и Singleton влияет на создание, совместное использование и освобождение объектов.

«Время жизни служб: Transient, Scoped, Singleton» — бесплатный урок C# Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Почему важен срок действия

Срок действия службы определяет как долго существует экземпляр и сколько экземпляров создаётся. Неправильный выбор приводит к трудноуловимым ошибкам, например утечке данных между запросами или чрезмерному созданию объектов.

Служба с временным сроком действия: новый экземпляр каждый раз

Службы с временным сроком действия создаются заново при каждом обращении к ним из контейнера. Используйте их для лёгких служб без состояния, если совместное использование состояния может быть опасным.

builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();

// Each resolution creates a new instance:
// var a = sp.GetRequiredService<IEmailSender>(); // new
// var b = sp.GetRequiredService<IEmailSender>(); // new (different)

Служба с областью действия: одна на запрос

Службы с областью действия создаются один раз для каждого scope — обычно для одного HTTP-запроса в ASP.NET Core. В рамках запроса используется один и тот же экземпляр, а для следующего запроса создаётся новый.

builder.Services.AddScoped<AppDbContext>();

// Within a single HTTP request:
// Both resolve to the SAME AppDbContext instance
// -> consistent unit of work across the request

Одиночная служба: одна на всё время работы приложения

Одиночные службы создаются один раз и повторно используются на протяжении всего времени работы приложения. Используйте их для ресурсоёмких при создании и безопасных в многопоточном режиме служб, например кэшей конфигурации.

builder.Services.AddSingleton<IMemoryCache, MemoryCache>();

// Or register a pre-built instance:
var config = new AppConfig { MaxRetries = 3 };
builder.Services.AddSingleton<IAppConfig>(config);

Сравнение всех трёх вариантов

Краткое сравнение:

  • С временным сроком действия — новый экземпляр при каждом запросе; утилиты без состояния
  • С областью действия — один экземпляр на HTTP-запрос; DbContext, единица работы
  • Одиночная — один экземпляр на всё время работы приложения; кэши, конфигурации

Проблема захваченной зависимости

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

// BAD: Singleton captures a Scoped service
public class MySingleton
{
    private readonly AppDbContext _db; // Scoped!
    public MySingleton(AppDbContext db) => _db = db;
    // _db is now stuck alive for the app's lifetime
}

Обнаружение нарушений области действия

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

builder.Host.UseDefaultServiceProvider(options =>
{
    options.ValidateScopes = true;   // detect captive deps
    options.ValidateOnBuild = true;  // fail fast at start
});

Службы с областью действия вне запроса

Чтобы получить службы с областью действия в фоновой задаче, создайте явную область с помощью IServiceScopeFactory. Никогда не получайте такие службы напрямую из корневого контейнера.

public class MyWorker : BackgroundService
{
    private readonly IServiceScopeFactory _factory;

    public MyWorker(IServiceScopeFactory factory) => _factory = factory;

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        using var scope = _factory.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        await db.Users.ToListAsync(ct);
    }
}

Освобождаемые службы с временным сроком действия

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

// Correctly scoped transient disposable
using var scope = sp.CreateScope();
var svc = scope.ServiceProvider.GetRequiredService<MyDisposableService>();
await svc.DoWorkAsync();
// svc.Dispose() called when scope is disposed

Выбор подходящего срока действия

Простое руководство:

  • Служба не имеет состояния? → С временным сроком действия
  • Она зависит от запроса (например, от удостоверения пользователя или DbContext)? → С областью действия
  • Она безопасна в многопоточном режиме и требует больших затрат на создание? → Одиночная

Практический пример: три срока действия вместе

Обычно веб-API регистрирует разные службы с подходящими сроками действия для обеспечения корректности и производительности.

builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
builder.Services.AddSingleton<ICacheService, RedisCacheService>();

builder.Services.AddScoped<AppDbContext>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<OrderService>();

builder.Services.AddTransient<IEmailSender, SendGridEmailSender>();

Быстрая проверка

Какая проблема возникает, когда одиночная служба удерживает ссылку на службу с областью действия?

Итоги: сроки действия служб

Главное:

  • С временным сроком действия: новый экземпляр при каждом обращении — подходит для служб без состояния и с небольшими затратами на создание
  • С областью действия: один экземпляр на запрос — DbContext, репозитории, единица работы
  • Одиночная: один экземпляр навсегда — кэши, конфигурация, безопасные в многопоточном режиме утилиты
  • Никогда не внедряйте краткоживущие службы в службы с более длительным сроком действия (захваченная зависимость)
  • Используйте IServiceScopeFactory, чтобы получать службы с областью действия в фоновых задачах

Часто задаваемые вопросы

Урок «Время жизни служб: Transient, Scoped, Singleton» бесплатный?

Да — полный текст урока «Время жизни служб: Transient, Scoped, Singleton» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Время жизни служб: Transient, Scoped, Singleton»?

Узнайте, как время жизни Transient, Scoped и Singleton влияет на создание, совместное использование и освобождение объектов. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Время жизни служб: Transient, Scoped, Singleton»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы контейнера внедрения зависимостей
  2. Время жизни служб: Transient, Scoped, Singleton
  3. Внедрение через конструктор и интерфейсы
  4. Шаблоны фабрики и параметров
← Назад к C# Academy