Подтвердить что ты не робот

Ввод конструктора в базовый класс с использованием autofac

У меня есть абстрактный базовый контроллер, у которого есть конструктор, который, как я надеялся, будет заполнен autofac, когда контроллеры будут построены.

public abstract class BaseController : Controller
{
    protected ILogger { get; private set; }

    protected BaseController()
    {
    }

    protected BaseController(ILogger logger)
    {
        Logger = logger;
    }
}

Это не работает, когда я получаю от него контроллер.

Я могу заставить это работать, когда я явно вызываю конструктор явно из контроллера. Это правильный способ сделать это?

public class PublicController : BaseController
{
    public PublicController()
    {
    }

    public PublicController(ILogger logger) : base(logger)
    {

    }
}

Кроме того, используя сборку mvc intergration, похоже, нет способа поделиться контейнером для других классов, чтобы сделать свое собственное решение. Я где-то читал, что это не поощряется, почему бы и нет? Разве это просто для того, чтобы отделить зависимость какой-либо единой инфраструктуры ioc? Является ли инжектор конструктора единственным способом заполнения зависимостей от heirachy.

Спасибо

4b9b3361

Ответ 1

Вызов конструктора базового класса явным образом является единственным способом сделать это с помощью вставки конструктора в С#. Похоже, вы должны удалить конструкторы без параметров без BaseController и PublicController, поскольку их никогда не следует вызывать, когда доступен журнал.

Проблема ввода зависимостей в базовый контроллер является общей с использованием ASP.NET MVC и IoC. Существует несколько вариантов/школ мысли.

1.) Используйте агрегированные услуги. Чтобы упростить конструкторы производных классов, создайте единую службу, которая предоставляет или делегирует все различные службы, необходимые базовому контроллеру (например, IBaseControllerDependencies или тому подобное.) Затем передайте эту службу в BaseController так же, как вы делаете с ILogger здесь.

В зависимости от вашего приложения и количества базовых классов, которые вы используете, есть разные плюсы/минусы. Google для "совокупных сервисов Autofac", чтобы узнать больше об этом.

2.) Используйте инъекцию свойств. Сделайте свойство ILogger в базовом классе общедоступным и настройте контейнер, используя:

builder.RegisterControllers().PropertiesAutowired();

В Autofac не используется предпочтительный метод вложения свойств. Роль конструктора заключается в том, чтобы принимать зависимости, тогда как записываемые свойства часто воспринимаются как запах кода, поэтому Autofac на самом деле не оптимизирует этот случай. Один из недостатков заключается в том, что записываемые свойства, которые не следует вводить часто, ошибочно, с нечетными последствиями.

3.) Функциональность базового контроллера Refactor в различных фильтрах действий. Autofac может вводить фильтры действий в конвейер вызова действия MVC. Таким образом, фильтры могут принимать зависимости, которые были в базовом классе, и те же проблемы могут быть применены сквозным способом. Подробнее об этом в Интернете, ExtensibleActionInvoker и .InjectActionInvoker() укажите информацию, которая вам нужна. Не всегда возможно со всеми проблемами.

4, также ответ на ваш второй вопрос.) Разрешите зависимости базового контроллера, используя местоположение службы из DependencyResolver.Current.

var logger = DependencyResolver.Current.GetService<ILogger>();

Причина, по которой это не рекомендуется, заключается в том, что она затрудняет понимание получаемого приложения, поскольку уже невозможно увидеть, от каких сервисов зависит компонент, глядя в одном месте (конструктор). Чтобы определить, что должно быть настроено в контейнере, прежде чем какой-либо конкретный компонент может быть использован, нужно найти всю кодовую базу компонента, чтобы найти вызовы GetService(). Заметное препятствие при тестировании устройства.

Надеюсь, это поможет, кусочек дампа мозга, который я знаю:) Другие, возможно, могут добавить к ним еще несколько идей.

Ответ 2

У меня нет привилегий для комментариев, чтобы запросить более подробную информацию, но мне нужно будет увидеть ваш регистрационный код, чтобы понять, чего вы ожидаете, и почему контейнер не отвечает этим ожиданиям.

Что касается ваших дополнительных вопросов: не обязательно, чтобы класс мог выполнить собственное разрешение, но класс может зависеть от автоматически разрешаемого объекта factory для известного типа (что наиболее часто бывает), Если вы зарегистрировали A, вы можете зависеть от Func<A>. В Autofac существует много типов отношений; см. http://code.google.com/p/autofac/wiki/RelationshipTypes.

"Совместное использование контейнера" обескураживается, потому что он имеет тенденцию скрывать зависимости класса. Если зависимость от контейнера принимается или упоминается как глобальный объект "IoC", то выражается выраженность конкретных зависимостей.

Устранение зависимостей по иерархии не должно быть проблемой, поскольку вы уже используете инъекцию c'tor. Я не уверен, что у вас проблема. Существуют дополнительные проблемы, такие как изменение всех ваших подклассов, если изменения базового класса меняются. К счастью, у Autofac есть ответ для этого в Aggregate Services (http://code.google.com/p/autofac/wiki/AggregateService).

Autofac - отличный, глубокий инструмент. Еще одно предложение, если вы только начинаете, уделите немного времени, чтобы обернуть голову вокруг объектов жизни и сроков жизни (особенно http://nblumhardt.com/2011/01/an-autofac-lifetime-primer/). Удачи!

Ответ 3

Autofac для .NET Core

Установить

PM> Install-Package Autofac.Core.NonPublicProperty

Использование

builder.RegisterType<AppService>()
  .AsImplementedInterfaces()
  .AutoWireNonPublicProperties();