Можно ли внедрять сервис с временем жизни Transient в контроллер ASP.NET Core?

«Можно ли внедрять сервис с временем жизни Transient в контроллер ASP.NET Core?» — вопрос из категории ASP.NET Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, можно. Это стандартная и допустимая практика.

  • Transient-сервисы создаются каждый раз, когда они запрашиваются из контейнера зависимостей (DI).
  • Контроллеры по умолчанию имеют время жизни Scoped (один экземпляр на HTTP-запрос).

Пример регистрации и внедрения:

// 1. Сервис (stateless - без внутреннего состояния)
public interface IIdGenerator { string GenerateId(); }
public class GuidIdGenerator : IIdGenerator
{
    public string GenerateId() => Guid.NewGuid().ToString();
}

// 2. Регистрация в DI (Program.cs или Startup.cs)
builder.Services.AddTransient<IIdGenerator, GuidIdGenerator>();

// 3. Внедрение в контроллер
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IIdGenerator _idGenerator;
    // При каждом запросе в этот контроллер будет внедрен НОВЫЙ экземпляр GuidIdGenerator
    public OrdersController(IIdGenerator idGenerator)
    {
        _idGenerator = idGenerator;
    }

    [HttpPost]
    public IActionResult CreateOrder()
    {
        var newId = _idGenerator.GenerateId(); // Используем сервис
        // ... логика создания заказа
        return Ok(new { id = newId });
    }
}

Когда это уместно:

  • Сервис является stateless (не хранит состояние между вызовами).
  • Сервис легковесный, и его создание не нагружает систему.
  • Вам нужен абсолютно новый экземпляр для каждой операции (например, генератор случайных чисел, маппер объектов).

О чем важно помнить:

  • Если Transient-сервис внедряется в Scoped или Singleton-сервис, он может неявно повысить свое время жизни, что иногда приводит к утечкам памяти (если он реализует IDisposable).
  • Для сервисов, которые должны разделять состояние в рамках одного запроса (например, кэш запроса), лучше использовать Scoped.