Castle Windsor - how to resolve by name?

南笙酒味 提交于 2019-12-06 12:01:03

Two years later, but I have a more elegant solution for other people that stummble accross this problem too. It is possible to use TypedFactory facility and adapt it to you needs like here. first create the factory interface (only! no need for the actual implementation, castle will take care of that):

public interface IHubProxyFactory
{
   IHubProxy GetProxy(string proxyName);
}

Now we need a class that extend the default typed facotory and retreives the component's name from the input (proxyName):

class NamedTypeFactory : DefaultTypedFactoryComponentSelector
{
    protected override string GetComponentName(MethodInfo method, object[] arguments)
    {
        string componentName = null;
        if (arguments!= null && arguments.Length > 0)
        {
            componentName = arguments[0] as string;
        }

        if (string.IsNullOrEmpty(componentName))
            componentName = base.GetComponentName(method, arguments);

        return componentName;
    }
}

And then register the factory with castle and specify that your NamedTypeFactory will be used:

Component.For<IHubProxyFactory>().AsFactory(new NamedTypeFactory())

Now every class can get the factory interface in its constructor:

public class SomeClass
{
    private IHubProxy _fooHub;
    private IHubProxy _barHub;

    public SomeClass(IHubProxyFactory hubProxyFactory)
    {
        _fooHub = hubProxyFactory.GetProxy("FooHub");
        _barHub = hubProxyFactory.GetProxy("BarHub");
    }
}

Okay, I think I've found a possible solution, partly using the approach detailed here which shows how it is possible to register Func<>s with Windsor.

First, I register a delegate (Func<>) that uses the container to resolve by name:-

Container.Register(Component.For<Func<string, IHubProxy>>()
                   .Instance(name => Container.Resolve<IHubProxy>(name))
                   .LifestyleSingleton());

Think of this as an IHubProxy "factory".

Next, I register my hub proxies as detailed in my original question:-

container.Register(Component.For<IHubProxy>()
               .UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("FooHub"))
               .LifestyleSingleton()
               .Named("FooHub"));
container.Register(Component.For<IHubProxy>()
               .UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("BarHub"))
               .LifestyleSingleton()
               .Named("BarHub"));

Here is an example of a class that needs instances of the hub proxies:-

public class SomeClass
{
    private IHubProxy _fooHub;
    private IHubProxy _barHub;

    public SomeClass(Func<string, IHubProxy> hubProxyFactory)
    {
        _fooHub = hubProxyFactory("FooHub");
        _barHub = hubProxyFactory("BarHub");
    }
}

Untried so far, but it looks promising. It's a clever solution but injecting the Func<> feels a little hacky, so I would still be keen to hear of other possible solutions to my problem.

I just used a similar method to yours. I use a typed Factory. Advantage is I have type safety for my hubs. Registering the hubs is the same. The rest differs a bit but is technical the same.

IServiceFactory { 
   IHubProxy GetFooHub();
   IHubProxy GetBarHub();
}

And Registration:

Container.AddFacility<TypedFactoryFacility>();
Container.Register(Component.For<IServiceFactory>().AsFactory());

Usage:

public class SomeClass
{
    private IHubProxy _fooHub;
    private IHubProxy _barHub;

    public SomeClass(IServiceFactry hubProxyFactory)
    {
        _fooHub = hubProxyFactory.GetFooHub();
        _barHub = hubProxyFactory.GetBarHub();
    }
}

Btw. Factory.Get"Name"() resolves by name.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!