Here is a simplification of my scenario.
I have some interfaces IFoo
, IBar
, and IBaz
with their implementations Foo
, Bar
and Baz
.
Foo
depends on IBar
and Bar
depends on IBaz
, so the dependency graph looks like this:
Foo
|
Bar
|
Baz
My Windsor config looks like this, and everything works as expected:
container.Register(Component.For<IFoo>().ImplementedBy<Foo>());
container.Register(Component.For<IBar>().ImplementedBy<Bar>());
container.Register(Component.For<IBaz>().ImplementedBy<Baz>());
Now I need to introduce a new SpecialBaz
, and I want to use it instead of the old Baz
when my dependency graph begins with a Foo
. The rest of the app will continue to the the old Baz
:
Foo SomethingElse
| |
Bar Bar
| |
SpecialBaz Baz
I have tried naming the SpecialBaz
with the ServiceOverride
api:
container.Register(Component.For<IBaz>().ImplementedBy<Baz>().IsDefault());
container.Register(Component.For<IBaz>().Named("special baz").ImplementedBy<SpecialBaz>());
container.Register(Component.For<IFoo>()
.ImplementedBy<Foo>()
.DependsOn(ServiceOverride.ForKey<IBaz>().Eq("special baz")));
And specifying the dependency:
container.Register(Component.For<IBaz>().ImplementedBy<Baz>().IsDefault());
container.Register(Component.For<IBaz>().ImplementedBy<SpecialBaz>());
container.Register(Component.For<IFoo>()
.ImplementedBy<Foo>()
.DependsOn(Component.For<IBaz>().ImplementedBy<SpecialBaz>()));
But neither approach worked.
Is this possible in Castle Windsor, and how do I wire it up?
The short answer is yes - Castle Windsor can. Every DI container can. I will offer you a rule to remember by which you can resolve most of your dependency problems.
The long answer.
The rule : Every point of indirection requires a layer of abstraction . Keep this rule in mind when you try to build dependency resolutions in apps. And there are two kinds of indirections as far as I know - static and dynamic.
You need to change the graph at one point and only once ( indirections ) but somehow you need to traverse the dependecies graph at runtime to see if your Baz is requested for Foo or not. So you need a factory of some kind( the abstraction thingie ).
You have two options depending on the answer of one question:
Is my change dependent on static or dynamic conditions?
For example - If you depend on incoming user data or environment data - you are in the dynamic case in which you will need yo use Dynamic Parameters or something else capable.
In your case your dependency is static.
and I want to use it instead of the old Baz when my dependency graph begins with a Foo.
The condition for special Baz never changes once the beginning of the graph is Foo.
You can achieve this with Factory method or Typed Factory Componend Selector. I provide you an example with Factory Method :
using System;
using Castle.MicroKernel.Registration;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var container = new Castle.Windsor.WindsorContainer();
container.Register(Component.For<IFoo>().ImplementedBy<Foo>());
container.Register(Component.For<ISomethingElse>().ImplementedBy<SomethingElse>());
container.Register(Component.For<IBar>().ImplementedBy<Bar>().LifeStyle.Transient);
container.Register
(
Component
.For<IBaz>()
.UsingFactoryMethod
(
(k, c) =>
{
IBaz resolved = null;
var requestingType = c.Handler.ComponentModel.Implementation;
if (requestingType == typeof(Foo))
{
resolved = new Baz();
}
else
{
resolved = new BazSpecial();
}
return resolved;
}
).LifeStyle.Transient
);
var f = container.Resolve<IFoo>();
var se = container.Resolve<ISomethingElse>();
Console.ReadLine();
}
}
internal interface IBar
{
}
internal interface IBaz
{
}
internal interface IFoo
{
}
interface ISomethingElse
{
}
internal class Bar : IBar
{
private readonly IBaz baz;
public Bar(IBaz baz)
{
this.baz = baz;
}
}
internal class Baz : IBaz
{
}
internal class BazSpecial : IBaz
{
}
internal class Foo : IFoo
{
private readonly IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
}
internal class SomethingElse : ISomethingElse
{
private readonly IBar bar;
public SomethingElse(IBar bar)
{
this.bar = bar;
}
}
}}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.