Skip to content

Посты

Когда использовать атрибут FromService

20 ноября 2019 г. • 3 мин чтения

Когда использовать атрибут FromService

Я недавно открыл для себя атрибут [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.

Единственный вариант использования, который я вижу для внедрения методов — это позднее связывание, когда зависимость не готова при создании контроллера. В противном случае лучше использовать внедрение через конструктор.

Я говорю это потому, что при внедрении через конструктор класс знает при создании, доступны ли зависимости. При внедрении методов это не так — неизвестно, доступны ли зависимости, пока метод не будет вызван.

Автор: Chuck Conway — инженер AI с почти 30-летним опытом разработки программного обеспечения. Он создает практические системы AI — конвейеры контента, агенты инфраструктуры и инструменты, которые решают реальные проблемы — и делится тем, что он узнает на этом пути. Свяжитесь с ним в социальных сетях: X (@chuckconway) или посетите его на YouTube и на SubStack.

↑ Вернуться в начало

Вам также может понравиться