Reputation: 11
I have a project where I am using Castle Windsor for the dependency injection, more specifically I am using the XML configuration so a common service can be run differently based on parameters.
For example (really simplified):
<component id="Processors" service="System.Collections.Generic.IEnumerable`1[[Services.Interfaces.IProcessor, Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]" type="System.Collections.Generic.List`1[[Services.Interfaces.IProcessor, Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]">
<parameters>
<collection>
<list>
<item>${Processor1}</item>
<item>${Processor2}</item>
</list>
</collection>
<parameters>
</component>
<component id="Processor1" service="Services.Interfaces.IProcessor" type="Services.TestProcessor, Services">
<parameters>
<example>LIVE</example>
<id>Processor1</id>
</parameters>
</component>
<component id="Processor2" service="Services.Interfaces.IProcessor" type="Services.TestProcessor, Services">
<parameters>
<example>TEST</example>
<id>Processor2</id>
</parameters>
</component>
At runtime we resolve the component named Processors and iterate through all of the items calling each one in turn.
As you can see in the above example we have a parameter called id on each of the processors, this is mostly being used for logging and is really useful tracking back to which processor has the issue (and by proxy the configuration). Ideally it would be nice if I could reuse the id from the component configuration (reducing the configuration).
Any ideas on how this can be done?
Upvotes: 1
Views: 457
Reputation: 11
For the use "component id/name as a parameter" part, you could define custom Castle.MicroKernel.ISubDependencyResolver
, for example like this:
public class InjectIdSubDependencyResolver : ISubDependencyResolver
{
private const string SpecialName = "id";
public bool CanResolve(
CreationContext context, ISubDependencyResolver contextHandlerResolver,
ComponentModel model, DependencyModel dependency)
=>
dependency.TargetType == typeof(string)
&&
dependency.DependencyKey == SpecialName
&&
dependency.Parameter?.ConfigValue == null;
public object Resolve(
CreationContext context, ISubDependencyResolver contextHandlerResolver,
ComponentModel model, DependencyModel dependency)
=> model.Name;
}
You set it up like this:
IWindsorContainer wc = ...;
wc.Kernel.Resolver.AddSubResolver(new InjectIdSubDependencyResolver());
Then XML config gets simplified ...
<component id="Processor1" service="Services.Interfaces.IProcessor" type="Services.TestProcessor, Services">
<parameters>
<example>LIVE</example>
</parameters>
</component>
<component id="Processor2" service="Services.Interfaces.IProcessor" type="Services.TestProcessor, Services">
<parameters>
<example>TEST</example>
</parameters>
</component>
Also, instead of registering generic list in container I would use some second class along with Collection Sub Dependency resolver, i.e.
public class Processors {
public Processors(IEnumerable<IProcessor> collection) { /**/ }
}
... or even try and use Typed Factories
Hope it helps.
Upvotes: 1