Бекенд на C# Web Api
Внедрение зависимостей

В C# WebApi внедрение зависимостей позволяет управлять жизненным циклом сервисов и делает код более гибким и модульным. В ASP.NET Core внедрение зависимостей встроено в фреймворк. Вот основные шаги для внедрения зависимостей:
Создание интерфейса и реализации: Создайте интерфейс для сервиса и его реализацию.
public interface IRegistrationService
{
async Task Register(RegistrationDto data);
}
public class EmailRegistrationService : IRegistrationService
{
public async Task Register(RegistrationDto data)
{ ... }
}
Регистрация зависимостей: Зарегистрируйте сервисы в контейнере зависимостей в методе
ConfigureServicesвProgram.cs.
var builder = WebApplication.CreateBuilder(args);
// Регистрация сервиса с жизненным циклом Singleton, Scoped или Transient
builder.Services.AddSingleton<IMyService, MyService>();
// или
builder.Services.AddScoped<IMyService, MyService>();
// или
builder.Services.AddTransient<IMyService, MyService>();
var app = builder.Build();Использование зависимостей: Теперь вы можете внедрять зависимости в контроллеры через конструктор.
[ApiController]
[Route("api/registration")]
public class RegistrationController : ControllerBase
{
private readonly IRegistrationService _registrationService;
// внедрение зависимости в конструктор контроллера
public MyController(IRegistrationService registrationService)
{
_registrationService = registrationService;
}
[HttpPost]
public async Task<IActionResult> Register([FromBody] RegistrationDto data)
{
var result = _registrationService.Register(data);
return Ok(result);
}
}
public class LoginService
{
private readonly IRegistrationService _registrationService;
// внедрение зависимости в конструктор другого сервиса
public LoginServive(IRegistrationService registrationService)
{
_registrationService = registrationService;
}
}В ASP.NET Core внедрение зависимостей поддерживает три основных жизненных цикла (время жизни объектов): Singleton, Scoped и Transient. Они определяют, как и когда создаются и уничтожаются объекты, зарегистрированные в контейнере зависимостей.
Экземпляр создается один раз при первом запросе и существует на протяжении всего жизненного цикла приложения. Все последующие запросы к этому сервису будут получать тот же экземпляр.
Использование: Когда сервис должен быть доступен во всём приложении и сохранять состояние (например, кэш, общие данные или настройки).
Пример использования: Сервис кэширования, логирования или любой другой сервис, который должен быть создан только один раз и использоваться всеми компонентами приложения.
Минусы:
Так как объект создается один раз и сохраняется в памяти, он может занимать ресурсы долгое время. Если экземпляр использует много памяти, это может привести к утечкам памяти.
Если сервис не потокобезопасен, его использование в нескольких потоках одновременно может вызвать проблемы.
Экземпляр создается один раз на каждый HTTP-запрос. Это значит, что каждый раз при обработке нового HTTP-запроса создается новый экземпляр зависимости, но в пределах одного запроса все инъекции этой зависимости будут получать один и тот же экземпляр.
Использование: Для сервисов, которые должны быть уникальны для каждого запроса, но могут повторно использоваться в рамках одного запроса.
Пример использования: Чаще всего используется для сервисов, которые работают с базами данных. Каждый запрос работает с отдельной транзакцией и набором данных, изолированным от других запросов.
Минусы:
Не подходит для долгоживущих сервисов, поскольку экземпляры создаются на каждый запрос и могут занимать больше ресурсов при высоком числе одновременных запросов.
Экземпляр создается каждый раз, когда он запрашивается. Это означает, что на каждый вызов зависимости будет создан новый объект.
Использование: Для сервисов, которые легковесны и не сохраняют состояние между вызовами. Такие сервисы могут быть быстро созданы и уничтожены.
Пример использования: В сценариях, где важна изоляция и каждый запрос должен работать с новым экземпляром (например, для сервисов, выполняющих простые операции, такие как преобразование данных, валидация и т.д.).
Минусы:
Если объект создается часто и его создание занимает много ресурсов, это может привести к увеличению времени отклика приложения.
Когда использовать:
Singleton:
Когда сервис должен существовать в одном экземпляре для всего приложения (например, кэш, логирование, статические данные).
Пример: глобальные сервисы кэширования или работы с конфигурацией приложения.
Scoped:
Когда сервис должен быть уникальным для каждого запроса, но одинаковым в рамках одного запроса.
Пример: любые сервисы, связанные с бизнес-логикой, зависящие от текущего запроса.
Transient:
Когда необходимо создавать новые экземпляры для каждой операции, чтобы не сохранять состояние между вызовами (например, сервисы для форматирования данных или отправки сообщений).
Пример: легковесные и stateless сервисы, работающие с краткосрочными задачами, такие как парсеры, валидация и др.
Жизненный цикл | Время жизни | Общий для всех запросов | Общий для одного запроса | Потокобезопасность требуется? |
|---|---|---|---|---|
Singleton | На протяжении всего приложения | Да | Да | Да |
Scoped | На протяжении одного запроса | Нет | Да | Не требуется, если запрос изолирован |
Transient | Новый экземпляр для каждого вызова | Нет | Нет | Не требуется |
Microsoft — Dependency Injection in ASP.NET Web API 2
Code Maze — Dependency Injection in ASP.NET Core
Code Maze — Dependency Injection Lifetimes in ASP.NET Core
Автор документа: Артём Ветик