How to programmatically register a component that depends on a list of already registered components with Castle Windsor?
I'm programmatically registering a group of se开发者_运维技巧rvices that all implement the same interface, IRule. I have another service that looks like this:
public class MyService {
private IEnumerable<IRule> _rules;
public MyService(IEnumerable<IRule> rules){
_rules = rules;
}
}
Hammett posted something that looked like what I wanted, http://hammett.castleproject.org/?p=257. I changed the signature to IRule[] and tried the ArrayResolver trick in the post but that didn't work for me(note, it didn't break anything either).
Anyone know how to programmatically register a component like the code I posted above?
If you don't want to change the signature of MyService and keep using IEnumerable<IRule>
, you can also create a custom ISubDependencyResolver. That's what we did:
public class EnumerableResolver : ISubDependencyResolver
{
private readonly IKernel kernel;
public EnumerableResolver(IKernel kernel)
{
this.kernel = kernel;
}
public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
Type targetType = dependency.TargetType;
if (targetType == null)
{
throw new ArgumentException("TargetType property cannot be null", "dependency");
}
if (targetType.IsGenericType && (targetType.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
{
Type service = targetType.GetGenericArguments()[0];
return this.kernel.HasComponent(service);
}
return false;
}
public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
Type service = dependency.TargetType.GetGenericArguments()[0];
Array array = this.kernel.ResolveAll(service, (IDictionary)null);
return Activator.CreateInstance(typeof(List<>).MakeGenericType(new Type[] { service }), new object[] { array });
}
}
It needs to be registered with the container like this:
container.Kernel.Resolver.AddSubResolver(new EnumerableResolver(this.Kernel));
I loaded up the source for Castle.MicroKernel, and noticed there is already an ArrayResolver and ListResolver(in the Castle.MicroKernel.Resolvers.SpecializedResolvers namespace). The code I copied(blindly) from Hammet's blog didn't work, most likely because the framework had changed since that was written.
Here's a sample project demonstrating how to do this: http://www.panteravb.com/downloads/WindsorCon.zip
I tried both the ArrayResolver and the ListResolver and they both worked without a hitch, it's pretty straightforward, so assuming this service class:
public class MyService
{
private IEnumerable<IRule> _rules;
public MyService(IList<IRule> rules)
{
_rules = rules;
}
}
you can register this guy like this:
private IWindsorContainer _container;
private void InitializeIoc()
{
_container = new WindsorContainer();
_container.Kernel.Resolver.AddSubResolver(new ListResolver(_container.Kernel));
_container.Register(Component.For<IRule>().ImplementedBy<Rule1>());
_container.Register(Component.For<IRule>().ImplementedBy<Rule2>());
_container.Register(Component.For<MyService>());
}
精彩评论