Reputation: 1062550
important; I'm really looking for a StructureMap
answer here. Please don't say how to do it with Windsor, Spring, Unity, or any of the others.
I'm playing with StructureMap
for IoC - and basically my aim is to have a "default" profile that defines the core types, and a number of named profiles that override/extend this. I think that profiles can do this, but I simply can't get it to work either through the xml or the code APIs. In particular, if I try to load a container for a profile:
container = new Container();
container.SetDefaultsToProfile(profile);
Then I get "Requested Profile {name} cannot be found", despite the fact that I clearly called CreateProfile
in the initialize (with that name).
Am I barking up the wrong tree?
(also posted to user-group)
What I ideally want is to be able to define the standard (/default) types, and then for a range of different named configurations, override some of the settings - i.e. if I had
IFoo
=> Foo
, IBar
=> Bar
IFoo
=> SpecialFoo
I believe this could map to 2 containers, loaded using named profiles.
The purpose being that if I ask either container for an IBar
, I get a
Bar
- but configA returns a Foo
(for IFoo
), where-as configB returns a
SpecialFoo
.
Can somebody give me a clue how I can configure this? Either xml or code is fine... I just want it to work. All I need is interface-to- concrete-type mappings (no special config/property settings).
Upvotes: 8
Views: 3210
Reputation: 36027
The trick is to make sure every single profile as at least a rule defined in it. If you don't specify a rule (configA) it won't create/see the profile.
Given these classes:
public interface IFoo { string SayHello(); }
public class Foo : IFoo { public string SayHello() { return "Hello"; } }
public class SpecialFoo : IFoo { public string SayHello() { return "Hello Special"; } }
public interface IBar { }
public class Bar : IBar { }
public interface IDummy { }
public class Dummy : IDummy{ }
You can define this registry:
public class MyRegistry : Registry
{
protected override void configure()
{
ForRequestedType<IBar>().TheDefault.Is.OfConcreteType<Bar>();
ForRequestedType<IFoo>().TheDefault.Is.OfConcreteType<Foo>();
CreateProfileNotEmpty("configA");
CreateProfileNotEmpty("configB")
.For<IFoo>().UseConcreteType<SpecialFoo>();
}
StructureMap.Configuration.DSL.Expressions.ProfileExpression CreateProfileNotEmpty(string profile)
{
return CreateProfile(profile)
.For<IDummy>().UseConcreteType<Dummy>();
}
}
And it will work with these tests:
[TestMethod]
public void TestMethod1()
{
var container = new Container(new MyRegistry());
Assert.IsNotNull(container.GetInstance<IBar>());
Assert.AreEqual("Hello", container.GetInstance<IFoo>().SayHello());
container.SetDefaultsToProfile("configB");
Assert.IsNotNull(container.GetInstance<IBar>());
Assert.AreEqual("Hello Special", container.GetInstance<IFoo>().SayHello());
container.SetDefaultsToProfile("configA");
Assert.IsNotNull(container.GetInstance<IBar>());
Assert.AreEqual("Hello", container.GetInstance<IFoo>().SayHello());
}
if you replace CreateProfileNotEmpty with simple CreateProfile, it will fail on the line that sets the default to configA.
Upvotes: 10
Reputation: 24368
Watch this video, he shows another way of doing the "default" profile and having other named profiles that would act as the variations.
http://www.dimecasts.net/Casts/CastDetails/135
Upvotes: 1