I'm getting close to code complete on the forthcoming 2.5 release of StructureMap and I'm focusing on ease of use features and fullblown interception support for AOP tooling (runtime AOP to be provided by something else though). StructureMap has had some support in the last couple releases to "fill" a concrete class with dependencies by calling ConcreteClass concreteClass = ObjectFactory.FillDependencies<ConcreteClass>(). The advantage being that you didn't have to explicitly register ConcreteClass with the configuration.
After
- Having somebody ask me how to do it
- Seeing a demo of another container do this (I'm not sure about my "NDA" on this, so I'm not gonna say which)
- Basically wanting a better way to do this for my current project
I decided to just add it.
As of today (in the trunk at least) you can simply request a concrete class through the normal ObjectFactory.GetInstance<T>() method, and if StructureMap can resolve the dependencies, ObjectFactory will happily return the class requested. Taking it a step farther, say you have a class with this constructor: public TradePresenter(Trade trade, ITradeView view, ITradeRepository repository). You can also do this now: TradePresenter presenter = ObjectFactory.With<Trade>(someTradeVariable).GetInstance<TradePresenter>() and you can get a TradePresenter object built with all of its dependencies (an ITradeView & ITradeRepository) plus pass the exact instance of the Trade class into the TradePresenter's constructor function.
All of this is in the Subversion trunk. If you feel like downloading it out of SVN and playing with it, I'd appreciate the feedback. Below is the unit test I'm using to prove out the implicit configuration:
[Test]
public void CanBuildConcreteTypesThatAreNotPreviouslyRegistered()
{ // Create a new InstanceManager that has a default instance configured for only the
// IProvider interface. InstanceManager is the real "container" behind ObjectFactory
Registry registry = new Registry();
registry.ForRequestedType<IProvider>().TheDefaultIsConcreteType<Provider>();
InstanceManager manager = (InstanceManager) registry.BuildInstanceManager();
// Now, have that same InstanceManager create a ClassThatUsesProvider. StructureMap will
// see that ClassThatUsesProvider is concrete, determine its constructor args, and build one
// for you with the default IProvider. No other configuration necessary.
ClassThatUsesProvider classThatUsesProvider = manager.CreateInstance<ClassThatUsesProvider>();
Assert.IsInstanceOfType(typeof(Provider), classThatUsesProvider.Provider);
}
Here's another example of using the new explicit arguments functionality. The relevant code is bolded:
[Test]
public void NowDoItWithObjectFactoryItself()
{ StructureMapConfiguration.ForRequestedType<ExplicitTarget>().TheDefaultIs(
Registry.Instance<ExplicitTarget>()
.UsingConcreteType<ExplicitTarget>()
.Child<IProvider>().IsConcreteType<RedProvider>()
.WithProperty("name").EqualTo("Jeremy") );
ObjectFactory.Reset();
// Get the ExplicitTarget without setting an explicit arg for IProvider
ExplicitTarget firstTarget = ObjectFactory.GetInstance<ExplicitTarget>();
Assert.IsInstanceOfType(typeof (RedProvider), firstTarget.Provider);
// Now, set the explicit arg for IProvider
BlueProvider theBlueProvider = new BlueProvider();
ExplicitTarget secondTarget = ObjectFactory.With<IProvider>(theBlueProvider).GetInstance<ExplicitTarget>();
Assert.AreSame(theBlueProvider, secondTarget.Provider);
}
Feedback on the syntax and/or usefulness of these features would be very appreciated.