Typed factory custom selector (Castle 2.5.1)

88 views
Skip to first unread message

Scott_M

unread,
Aug 16, 2011, 7:43:00 PM8/16/11
to castle-pro...@googlegroups.com
I have a typed factory with a custom selector.  I basically need to be able to have a typed factory that selects the component via componentName passed in as a method argument to the factory method.  It all seems to work when I pass a valid componentName in.  However, when I pass an invalid componentName in things go afoul.  Specifically, castle somehow manages to match another component that has the correct type but wrong name.  How do you force castle to return null or throw an error in this situation?  Here is my code:


IWindsorContainer container = new WindsorContainer();

            //must register typed factory facility otherwise we get errors
            container.AddFacility<TypedFactoryFacility>();

            container.Register(
                Component.For<IFoo>().ImplementedBy<Foo1>().Named("Foo1").LifeStyle.Transient,
                Component.For<IFoo>().ImplementedBy<Foo2>().Named("Foo2").LifeStyle.Transient,
                Component.For<IFooFactoryWithArgs>().AsFactory(c => c.SelectedWith("MySelector")),
                Component.For<ITypedFactoryComponentSelector>().ImplementedBy<SelectorByComponentName>().Named("MySelector")
                );

            IFooFactoryWithArgs factory = container.Resolve<IFooFactoryWithArgs>();

            IFoo foo = factory.GetFoo("Foo3");  //Note, there is no component registered with Foo3 so I would expect NULL to be returned or an error thrown at this point.  Unfortunately, Foo1 is returned.

            Assert.IsNotNull(foo);

            Assert.IsTrue(foo.GetType() == typeof(Foo2));

public class SelectorByComponentName : DefaultTypedFactoryComponentSelector
    {               
        protected override string GetComponentName(MethodInfo method, object[] arguments)
        {
            bool found = false;
            int position = -1;
            object componentArgument = null;
            string componentName = null;

            ParameterInfo[] pInfos = method.GetParameters();
            if (pInfos != null)
            {
                foreach (ParameterInfo pInfo in pInfos)
                {
                    if (pInfo.Name.ToLower() == "componentname")
                    {
                        found = true;
                        position = pInfo.Position;
                        break;
                    }
                }
            }

            if (!found)
            {
                throw new ApplicationException("The current component selctor did not find a 'componentname' argument for the current factory method.");
            }

            componentArgument = arguments[position];
            if (componentArgument == null)
            {
                throw new ApplicationException("The current component selctor found a null 'componentname' argument for the current factory method.");
            }

            componentName = componentArgument.ToString();  //no way to validate that we have a valid / registered component name
            if (String.IsNullOrEmpty(componentName))
            {
                throw new ApplicationException("The current component selctor found a null or empty 'componentname' argument for the current factory method.");
            }

            return componentName;
        }

        protected override IDictionary GetArguments(MethodInfo method, object[] arguments)
        {
            var argumentMap = new Arguments();

            return argumentMap;  //No additional arguments
        }
    }

Krzysztof Koźmic

unread,
Aug 16, 2011, 10:20:28 PM8/16/11
to castle-pro...@googlegroups.com
That's a known issue/feature, and the reason for that was to handle
scenarios where with default selector you had factory method named like
GetFoo. In that case factory would first try to get component named
"Foo" and then fallback to getting it by type if not found. The problem
is no distinction was being made between this implicit lookup by name
and implicit one, when you specify the name yourself in a custom selector.

This is handled a bit better in v3 which makes the distinction and if
you request lookup by name explicitly the lookup will fail if component
with that name is not present.
If you don't want to upgrade to v3 just yet, I think your option is to
use custom selector that returns custom TypedFactoryComponent and
override Resolve method of the component to provide your desired behaviour.

HTH,
Krzysztof

> --
> You received this message because you are subscribed to the Google
> Groups "Castle Project Users" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/castle-project-users/-/VW5vNsD15UIJ.
> To post to this group, send email to
> castle-pro...@googlegroups.com.
> To unsubscribe from this group, send email to
> castle-project-u...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/castle-project-users?hl=en.

Reply all
Reply to author
Forward
0 new messages