简体   繁体   English

Castle Windsor 接口的多种实现

[英]Castle Windsor multiple implementations of interface

I have the following installer but for some odd reason it is not resolving correctly.我有以下安装程序,但由于某些奇怪的原因,它无法正确解析。 I have an interface where there are 2 implementations of it but want to inject the correct instance based on naming conventions .我有一个接口,其中有 2 个实现,但想根据naming conventions注入正确的实例。

I am expecting in this instance that the correct instance of ICommand will be injected based on how they are named.我期望在这种情况下,将根据它们的命名方式注入正确的ICommand实例。 However, for some odd reason both controllers are picking the very first instance, ie FooCommand due to it being defined first in the installer.然而,出于某种奇怪的原因,两个控制器都选择了第一个实例,即FooCommand因为它是在安装程序中首先定义的。

Not sure what I have done wrong?不确定我做错了什么? Perhaps, is there an alternative way of doing this?也许,有没有其他方法可以做到这一点?

public interface ICommand { }

public class FooCommand : ICommand { }

public class BarCommand : ICommand { }

public class SomeController : ApiController
{
    public SomeController(ICommand fooCommand) { }
}

public class HelloController : ApiController
{
    public HelloController(ICommand barCommand) { }
}

container.Register(
    Component.For<ICommand>()
        .Named("fooCommand")
        .ImplementedBy<FooCommand>()
        .LifestyleSingleton(),
    Component.For<ICommand>()
        .Named("barCommand")
        .ImplementedBy<BarCommand>()
        .LifestyleSingleton());

Like @steven said, it's generally not a good idea and if not managed properly may lead to discoverability issues down the line, but assuming you know what you're doing you can build a IContributeComponentModelConstruction that will match constructor parameters of type ICommand on your controllers with Windsor components having the same name.就像@steven 所说的那样,这通常不是一个好主意,如果管理不当可能会导致可发现性问题,但假设您知道自己在做什么,您可以构建一个IContributeComponentModelConstruction来匹配控制器上ICommand类型的构造函数参数具有相同名称的 Windsor 组件。

public class ControllerCommandMatcher : IContributeComponentModelConstruction
{
    public void ProcessModel(IKernel kernel, ComponentModel model)
    {
        // or whatever other condition to bail out quickly
        if (model.Implementation.Name.EndsWith("Controller") == false) return;

        foreach (var constructor in model.Constructors)
        {
            foreach (var dependency in constructor.Dependencies)
            {
                if (dependency.TargetItemType != typeof (ICommand)) continue;
                dependency.Parameter = new ParameterModel(dependency.DependencyKey,
                    ReferenceExpressionUtil.BuildReference(dependency.DependencyKey));
            }
        }
    }
}

The tricky bit is this:棘手的一点是:

new ParameterModel(dependency.DependencyKey,
       ReferenceExpressionUtil.BuildReference(dependency.DependencyKey))

It basically tells Windsor that the dependency (the constructor parameter), for example fooCommand should be satisfied with a component of the same name ( fooCommand ).它基本上告诉 Windsor 依赖项(构造函数参数),例如fooCommand应该满足同名组件( fooCommand )。

Then add your contributor to the container然后将您的贡献者添加到容器中

container.Kernel.ComponentModelBuilder.AddContributor(new ControllerCommandMatcher());

Here's the documentation 这是文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM