← Назад к вопросам
Приведи пример использования DI в ASP.NET Core
2.0 Middle🔥 171 комментариев
#ASP.NET и Web API
Комментарии (1)
🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример внедрения зависимостей в ASP.NET Core
Внедрение зависимостей (Dependency Injection, DI) — это фундаментальный паттерн в ASP.NET Core, который позволяет создавать слабосвязанные, тестируемые и поддерживаемые приложения. Рассмотрим полный пример с регистрацией сервисов, их внедрением и использованием.
1. Создание интерфейсов и сервисов
Сначала определим контракты и их реализации:
// Интерфейс для службы работы с email
public interface IEmailService
{
Task SendEmailAsync(string to, string subject, string body);
}
// Реализация службы email
public class SmtpEmailService : IEmailService
{
private readonly ILogger<SmtpEmailService> _logger;
public SmtpEmailService(ILogger<SmtpEmailService> logger)
{
_logger = logger;
}
public async Task SendEmailAsync(string to, string subject, string body)
{
_logger.LogInformation($"Отправка email на {to}: {subject}");
// Реальная логика отправки через SMTP
await Task.Delay(100); // Имитация отправки
}
}
// Интерфейс репозитория пользователей
public interface IUserRepository
{
Task<User> GetUserByIdAsync(int id);
Task AddUserAsync(User user);
}
// Модель пользователя
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Name { get; set; }
}
// Реализация репозитория
public class UserRepository : IUserRepository
{
private readonly List<User> _users = new();
public Task<User> GetUserByIdAsync(int id)
{
var user = _users.FirstOrDefault(u => u.Id == id);
return Task.FromResult(user);
}
public Task AddUserAsync(User user)
{
_users.Add(user);
return Task.CompletedTask;
}
}
2. Сервис бизнес-логики с внедрением зависимостей
public class UserService
{
private readonly IUserRepository _userRepository;
private readonly IEmailService _emailService;
private readonly ILogger<UserService> _logger;
// Конструктор с внедрением зависимостей
public UserService(
IUserRepository userRepository,
IEmailService emailService,
ILogger<UserService> logger)
{
_userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
_emailService = emailService ?? throw new ArgumentNullException(nameof(emailService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task RegisterUserAsync(User user)
{
_logger.LogInformation($"Регистрация пользователя: {user.Name}");
// Сохраняем пользователя
await _userRepository.AddUserAsync(user);
// Отправляем приветственное письмо
await _emailService.SendEmailAsync(
user.Email,
"Добро пожаловать!",
$"Уважаемый {user.Name}, спасибо за регистрацию!");
}
}
3. Конфигурация DI контейнера в Program.cs
var builder = WebApplication.CreateBuilder(args);
// Регистрация сервисов в DI контейнере
builder.Services.AddScoped<IEmailService, SmtpEmailService>();
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<UserService>();
// Регистрация контроллера
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
4. Использование в контроллере
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly UserService _userService;
private readonly ILogger<UsersController> _logger;
// DI автоматически внедрит зависимости через конструктор
public UsersController(UserService userService, ILogger<UsersController> logger)
{
_userService = userService;
_logger = logger;
}
[HttpPost]
public async Task<IActionResult> CreateUser([FromBody] User user)
{
_logger.LogInformation("Создание нового пользователя");
try
{
await _userService.RegisterUserAsync(user);
return Ok(new { Message = "Пользователь успешно создан" });
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при создании пользователя");
return StatusCode(500, "Внутренняя ошибка сервера");
}
}
}
5. Варианты времени жизни сервисов
// В Program.cs можно настроить разные времена жизни:
builder.Services.AddTransient<ITransientService, TransientService>(); // Новый экземпляр каждый раз
builder.Services.AddScoped<IScopedService, ScopedService>(); // Один экземпляр на запрос
builder.Services.AddSingleton<ISingletonService, SingletonService>(); // Один экземпляр на всё приложение
// Регистрация с фабричным методом
builder.Services.AddScoped<IEmailService>(provider =>
{
var config = provider.GetRequiredService<IConfiguration>();
var logger = provider.GetRequiredService<ILogger<SmtpEmailService>>();
return new SmtpEmailService(logger)
{
SmtpServer = config["EmailSettings:SmtpServer"]
};
});
// Регистрация нескольких реализаций
builder.Services.AddScoped<IEmailService, SmtpEmailService>();
builder.Services.AddScoped<IEmailService, SendGridEmailService>(); // Альтернативная реализация
6. Внедрение зависимостей в минимальные API
app.MapPost("/api/users/minimal", async (
[FromBody] User user,
[FromServices] UserService userService, // Явное указание зависимости
ILogger<Program> logger) => // Автоматическое внедрение
{
logger.LogInformation("Minimal API: создание пользователя");
await userService.RegisterUserAsync(user);
return Results.Ok(new { Message = "Пользователь создан через Minimal API" });
});
// С использованием групп
var userGroup = app.MapGroup("/api/users")
.WithTags("Users")
.WithOpenApi();
userGroup.MapPost("/", async (User user, UserService service) =>
{
await service.RegisterUserAsync(user);
return Results.Created($"/api/users/{user.Id}", user);
});
Ключевые преимущества DI в ASP.NET Core:
- Слабосвязность: Компоненты зависят от абстракций, а не от конкретных реализаций
- Тестируемость: Легко подменять реализации моками при юнит-тестировании
- Управление временем жизни: Гибкая настройка времени жизни объектов
- Упрощение конфигурации: Централизованная регистрация всех зависимостей
- Автоматическое разрешение: Контейнер сам создает и внедряет зависимости
Пример юнит-теста с использованием DI:
[Test]
public async Task RegisterUser_SendsWelcomeEmail()
{
// Arrange
var mockEmailService = new Mock<IEmailService>();
var mockRepository = new Mock<IUserRepository>();
var mockLogger = new Mock<ILogger<UserService>>();
var userService = new UserService(
mockRepository.Object,
mockEmailService.Object,
mockLogger.Object);
var user = new User { Id = 1, Email = "test@example.com", Name = "Test" };
// Act
await userService.RegisterUserAsync(user);
// Assert
mockEmailService.Verify(
es => es.SendEmailAsync(
"test@example.com",
"Добро пожаловать!",
It.IsAny<string>()),
Times.Once);
}
Данный пример демонстрирует полный цикл использования DI в ASP.NET Core: от определения интерфейсов до их регистрации и внедрения в контроллеры и сервисы. Такой подход делает код более модульным, тестируемым и легким для поддержки.