
Недавно я обнаружил атрибут [FromServices]
, который является частью .Net Core с первой версии.
Атрибут [FromServices] позволяет внедрение зависимостей на уровне методов в контроллерах Asp.Net Core.
Вот пример:
public class UserController : Controller
{
private readonly IApplicationSettings _applicationSettings;
public UserController(IApplicationSettings applicationSettings)
{
_applicationSettings = applicationSettings;
}
public IActionResult Get([FromService]IUserRepository userRepository, int userId)
{
//Do magic
}
}
Зачем использовать внедрение через метод вместо внедрения через конструктор? Обычное объяснение заключается в том, что когда методу нужны зависимости, которые не используются больше нигде, то это кандидат для использования атрибута [FromService]
.
Steven с StackOverflow опубликовал ответ против использования атрибута [FromService]
:
Для меня использование такого типа внедрения методов в действия контроллера - плохая идея, потому что:
– Такой атрибут
[FromServices]
можно легко забыть, и вы узнаете об этом только при вызове действия (вместо того чтобы узнать при запуске приложения, где можно проверить конфигурацию приложения)– Необходимость отказаться от внедрения через конструктор по соображениям производительности является явным признаком того, что внедряемые компоненты слишком тяжелы для создания, в то время как конструкторы внедрения должны быть простыми, и создание компонентов должно, следовательно, быть очень легковесным.
– Необходимость отказаться от внедрения через конструктор, чтобы предотвратить слишком большие конструкторы, является признаком того, что ваши классы имеют слишком много зависимостей и становятся слишком сложными. Другими словами, наличие многих зависимостей является признаком того, что класс нарушает Принцип единственной ответственности. Тот факт, что действия вашего контроллера можно легко разделить между разными классами, является доказательством того, что такой контроллер не очень связан и, следовательно, признаком нарушения SRP.
Поэтому вместо сокрытия основной проблемы с использованием внедрения методов, я советую использовать внедрение через конструктор как единственный паттерн внедрения здесь и делать ваши контроллеры меньше. Это может означать, однако, что ваша схема маршрутизации станет отличаться от структуры ваших классов, но это совершенно нормально и полностью поддерживается ASP.NET Core.
С точки зрения тестируемости, кстати, не должно иметь большого значения, если иногда есть зависимость, которая не нужна. Существуют эффективные паттерны тестирования, которые решают эту проблему.
Я согласен со Steven; если вам нужно перенести зависимости из контроллера в метод, потому что класс конструирует слишком много зависимостей, то пришло время разбить контроллер. Вы почти наверняка нарушаете SRP.
Единственный случай использования, который я вижу для внедрения методов, - это позднее связывание, когда зависимость не готова при конструировании контроллера. В противном случае лучше использовать внедрение через конструктор.
Я говорю это потому, что при внедрении через конструктор класс знает при конструировании, доступны ли зависимости. При внедрении методов это не так, неизвестно, доступны ли зависимости, пока не будет вызван метод.
Автор: Чак Конвей специализируется на разработке программного обеспечения и генеративном ИИ. Свяжитесь с ним в социальных сетях: X (@chuckconway) или посетите его на YouTube.