I have a need for a cyclic dependency in Windsor. This is on purpose for a recursive approach. Module A calls Modules B-F and Module B needs to call back into A because of a tree of nodes.
Anyway, I know I can't use constructor injection because of this. So I set up Module A with property injection to get an IEnumerable<IModule>.
I've registered all of the types but when resolving Module A, Windsor is setting the property with Null (I have it throw an exception). I tried using DependsOn, but that seems to apply only to constructor arguments.
How can I get Windsor to resolve my collection of modules B-F into module A via property injection so I can have the dependency cycle I need?
Here's the top level module (Module A) and IModule;
public interface IModule
{
bool IsAccessibleToUser(INode node);
}
public class CompositeModule:IModule
{
private IEnumerable<IModule> innerModules;
public IEnumerable<IModule> InnerModules
{
get { return innerModules; }
set {
if (null == innerModules) throw new ArgumentNullException("innerModules");
innerModules = value;
}
}
public CompositeModule()
{
InnerModules = new List<IModule>();
}
public bool IsAccessibleToUser(INode node)
{
return innerModules.All(module => module.IsAccessibleToUser(node));
}
}
And the recursive submodule:
public class CheckChildrenModule : IModule
{
private IModule compositeModule;
public CheckChildrenModule(IModule compositeModule)
{
if (null == compositeModule) throw new ArgumentNullException("compositeModule");
this.compositeModule = compositeModule;
}
public bool IsAccessibleToUser(INode node)
{
var attributes = node.Attributes;
if (!attributes.ContainsKey("checkchildren")) return true;
string checkchildren = attributes["checkchildren"].ToString();
if (checkchildren.ToLower() == bool.TrueString.ToLower())
{
//look for any child with result of TRUE and stop immediately if found in order to be efficient.
return node.ChildNodes.Any(childNode => compositeModule.IsAccessibleToUser(childNode));
}
return true; //check false or some other value. return true!
}
}
And my registration:
// Configure Windsor to resolve arrays in constructors
container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel, true));
//collections too
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
//other stuff here
container.Register(Component.For<IModule>()
.ImplementedBy<CompositeModule>()
.Named("CompositeModule1"));
container.Register(Component.For<IModule>().ImplementedBy<CheckChildrenModule>()
.DependsOn(ServiceOverride.ForKey<IModule>().Eq("CompositeModule1")));
//A few other IModules here, all of which should be passed to the Composite Module "innerModules" property.
As I said, I tried DependsOn, which doesn't seem to apply to properties, and also PropertyRequire, which had no effect, I still got passed a null.
Note that I do not have access to the Container.Resolve code, as I'm registering these components for a 3rd party tool.
Thanks!
EDIT
What I expect:
Windsor resolves CompositeModule and creates an instance using default ctor. Names it.
Windsor goes to satisfy the property, which is an enumerable of IModules
It sees 6 IModules, not counting CompositeModule, and tries to instantiate them into a collection
It sees that one of the 6 modules, CheckChildrenModule, requires the named instance of CompositeModule.
It uses the named instance of CompositeModule created in Step 1 to satisfy the ctor dependency on CheckChildrenModule
Now it can finish the collection of IModules and pass them into the InnerModules property of CompositeModule, from step 2.
Just don't know how to get it to happen.
IModule
have theInnerModules
property? – fra9001