Как использовать типизированную фабрику для разрешения компонентов, которые принимают параметры при использовании регистрации на основе соглашения? - PullRequest
0 голосов
/ 06 ноября 2018

Виндзорский документ говорит, что мы можем передать параметры в TypedFactory вызовах метода, и эти параметры будут переданы в конструктор типа, который создает фабрика:

Вы также можете использовать методы, которые принимают параметры от вызывающей стороны для разрешения компонентов. Передаваемый аргумент будет передан конвейеру разрешения контейнера.

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

Например, возьмите следующий код:

public interface IWatcherFactory : IDisposable
{
    IWatcher GetWatcher(ImportTarget importTarget);
}

который зарегистрирован с container.Register(Component.For<IWatcherFactory>().AsFactory());

public class FolderWatcher : WatcherBase
{
    public FolderWatcher(ImportTarget importTarget, ILogger logger, IClock clock, IFileSystem fileSystem)
        : base(importTarget, logger)
    {
        // ...
    }
}

, где WatcherBase -

public abstract class WatcherBase : IWatcher
{
    public WatcherBase(ImportTarget importTarget, ILogger logger)
    {
        // ...
    }
}

которые зарегистрированы с container.Register(Classes.FromThisAssembly().BasedOn<IWatcher>().WithServiceAllInterfaces().LifestyleTransient());

Теперь другие вопросы и ответы скажем имена параметров должны совпадать, чтобы это работало, что мое уже делает.

Это точная ошибка, которую я получаю:

'FolderWatcher' is waiting for the following dependencies:
- Service 'ImportTarget' which was not registered.

Мне кажется, проблема в том, что Виндзор ничего не говорит о том, что зависимость от ImportTarget существует из-за регистрации соглашения, но я не уверен.

У меня также есть селектор компонентов, который выглядит следующим образом:

public class WatcherFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
    protected override string GetComponentName(MethodInfo method, object[] arguments)
    {
        var config = arguments.FirstOrDefault() as ImportTarget;
        if (config == null)
        {
            return base.GetComponentName(method, arguments);
        }

        return config.WatcherFullyQualifiedName;
    }
}

которое зарегистрировано так: container.Register(Component.For<ITypedFactoryComponentSelector>().ImplementedBy<WatcherFactoryComponentSelector>());

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

Итак, вопрос охватывает две связанные, но отдельные темы. Я отвечу на них по очереди.

Почему Виндзор жалуется на отсутствие ImportTarget зависимости?

Это не имеет никакого отношения к тому, как вы регистрируете свои компоненты, будь то по соглашению, по одному или (пожалуйста, не) с XML.

Имейте в виду, что Виндзор ошибается в безопасности, и он не предполагает, что вы только когда-либо получите зависимость от FolderWatcher, используя типизированный фабричный метод. Он пытается работать с тем, что у него есть, то есть он смотрит на компоненты, о которых он знает, и, поняв, что его нет, для ImportTarget он выдает это сообщение.

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

Теперь (ссылаясь на ваш собственный ответ), регистрация Component.For<ImportTarget>() сделает Виндзор заткнувшимся об этом, но я предполагаю (не видя остальную часть вашего кода) простой ImportTarget, как тот, который вы хотели бы get by new ImportTarget() не очень полезен без правильной установки WatcherFullyQualifiedName. Так что это маскирует проблему, а не исправляет ее.

Как правильно подключить селектор компонента к типизированной фабрике?

Это легко - вы все сделали правильно. Лично, если вы не используете его для других фабрик в другом месте, я бы даже не стал регистрировать WatcherFactoryComponentSelector в контейнере, но пошел бы .AsFactory(cfg => cfg.SelectedWith(new WatcherFactoryComponentSelector())), но это второстепенный момент.

0 голосов
/ 07 ноября 2018

Так что, похоже, все, что мне нужно было сделать, - это зарегистрировать ImportTarget в контейнере, который, похоже, сделал свою работу.

container.Register(Component.For<ImportTarget>());

Мне также нужно было изменить способ регистрации моего IWatcherFactory:

container.Register(Component.For<WatcherFactoryComponentSelector>());
container.Register(Component.For<IWatcherFactory>().AsFactory(cfg => cfg.SelectedWith<WatcherFactoryComponentSelector>()));

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

...