使用基于约定的注册时,如何使用类型化的工厂解析采用参数的组件?

时间:2018-11-06 13:28:48

标签: c# dependency-injection inversion-of-control castle-windsor conventions

温莎的docs说我们可以在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());

中注册的

现在还有其他问题和答案say,参数名称需要与此匹配才能起作用,而我已经做到了。

这是我得到的确切错误:

'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 :(得分:1)

因此,问题涵盖了两个相关但独立的主题。我会依次回答。

温莎为什么抱怨缺少ImportTarget依存关系?

这与您注册组件的方式没有任何关系,无论是按照惯例,是一个接一个还是(请不要)使用XML。

请记住,温莎在安全方面犯了错误,并且不认为您会使用类型化工厂方法来获得对FolderWatcher的依赖。 它会尝试使用现有功能-也就是说,它会调查它确实知道的组件,并且在意识到ImportTarget中没有它的情况下,会产生此消息。

请注意,这不是错误,而是更多警告。在这里引起您的注意的事实是,如果您尝试直接直接依赖于FolderWatcher,那么您将失败。

现在(参考您自己的回答),注册一个Component.For<ImportTarget>()会使Windsor闭嘴,但是我猜(没有看到您的其余代码)是一个普通的ImportTarget,就像如果没有正确设置new ImportTarget(),那么WatcherFullyQualifiedName会给您带来的帮助不是很有用。这样就掩盖了问题,而不是解决问题。

将组件选择器连接到类型化工厂的正确方法是什么?

这很容易-您在这里做对了。 就个人而言,除非您将其用于其他地方的其他工厂,否则我什至都不会在容器中注册WatcherFactoryComponentSelector,而是去.AsFactory(cfg => cfg.SelectedWith(new WatcherFactoryComponentSelector())),但这只是次要的事情。

答案 1 :(得分:0)

所以看来我需要做的就是在容器中注册ImportTarget,这似乎已经完成了工作。

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

我还需要更改注册IWatcherFactory的方式:

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

免责声明:我不知道这是否是正确的处理方式,但是现在它可以正常工作,因此我会一直使用它,直到出现其他问题