2

I am trying to create a dependency graph in StructureMap 3 with a chain of decorators:

Each instance has a constructor with multiple arugments, but exactly one argument of an inner IGeocoder, e.g.

public SomeCachingGeocoder(IGeoCoder inner, IFoo somethingElse)

I am hooking them up like this:

For<OviGeoCoder>().Use<OviGeoCoder>();
For<SqlCachingGeocoder>().Use<SqlCachingGeocoder>().Ctor<IGeoCoder>().Is<OviGeoCoder>();
For<RedisCachingGeocoder>().Use<RedisCachingGeocoder>().Ctor<IGeoCoder>().Is<SqlCachingGeocoder>();
For<IGeoCoder>().Use<RedisCachingGeocoder>();

But I get

Bi-directional dependency relationship detected! Check the StructureMap stacktrace below:
1.) Instance of SOAM.Services.IGeoCoder (SOAM.Services.Geocoding.RedisCachingGeocoder)
2.) new RedisCachingGeocoder(Default of IDatabase, Default of IGeoCoder)
3.) SOAM.Services.Geocoding.RedisCachingGeocoder
4.) Instance of SOAM.Services.IGeoCoder (SOAM.Services.Geocoding.RedisCachingGeocoder)
5.) new HomeController(Default of IGeoCoder, Default of IAlertService)
6.) SOAM.Web.Controllers.HomeController
7.) Instance of SOAM.Web.Controllers.HomeController
8.) Container.GetInstance(SOAM.Web.Controllers.HomeController)

Any ideas how to solve this?

Jon Bates
  • 3,055
  • 2
  • 30
  • 48
  • Why don't you use the `DecorateAllWith` method as shown [here](https://stackoverflow.com/a/25136317/264697)? – Steven Dec 22 '14 at 17:57
  • I dont want to decorate all instances with a specific decorator, i want to decorate A with B, B with C and C with D etc. DecorateWith also doesnt (as far as I could see) allow for injection; you need to create the instance yourself. – Jon Bates Dec 22 '14 at 21:15

2 Answers2

4

DecorateAllWith allows auto-wiring by default and allows stacking decorators in a quite easy way:

For<IGeoCoder>().Use<OviGeoCoder>();
For(typeof(IGeoCoder)).DecorateAllWith(typeof(SqlCachingGeocoder));
For(typeof(IGeoCoder)).DecorateAllWith(typeof(RedisCachingGeocoder));
Steven
  • 166,672
  • 24
  • 332
  • 435
2

If for some reason you cannot use DecorateAllWith() then this should work:

        var container = new Container(
            c =>
                {
                    c.For<IFoo>().Use<Foo>();
                    c.For<IGeoCoder>().Add<OviGeoCoder>().Named("default");
                    c.For<IGeoCoder>()
                        .Add<SqlCachingGeocoder>()
                        .Ctor<IGeoCoder>()
                        .Is(ctx => ctx.GetInstance<IGeoCoder>("default"))
                        .Named("SqlCaching");
                    c.For<IGeoCoder>()
                        .Use<RedisCachingGeocoder>()
                        .Ctor<IGeoCoder>()
                        .Is(ctx => ctx.GetInstance<IGeoCoder>("SqlCaching"));
                });

Wanna find what's the difference when using Use vs Add? Take a look here

Community
  • 1
  • 1
LetMeCodeThis
  • 591
  • 6
  • 10