Forget the neverending argument on the ALT.NET list about whether or not it’s acceptable to inject services into an Entity object (for the record, I say “no way”). What if you want to go the other way around? What if you want to request a service or a view or a command of some kind and have an Entity injected into the service/view/command? You’ve now got (at least) 2 ways to do that in StructureMap.
If you already have the Entity
If you’ve already got the Entity you want, you “pass” the Entity object into ObjectFactory (or an IContainer). Let’s say you have a view named TradeView like this:
public class TradeView : IView { private readonly Trade _trade; public TradeView(Trade trade) { _trade = trade; } public Trade Trade { get { return _trade; } } }
If you already have the Trade object in memory, you can grab the IView that displays the Trade by using the Container.With().GetInstance<T>() methods:
[Test] public void Example() { IContainer container = new Container(); Trade theTrade = new Trade(); var view = container.With<Trade>(theTrade).GetInstance<TradeView>(); view.Trade.ShouldBeTheSameAs(theTrade); }
The “explicit arguments” to GetInstance<T>() will be propogated all the way through the object graph. Let’s say we have a class named Command that takes in an IView, a Trade, and a Node object in its constructor. The actual object passed to the Command constructor might be a TradeNode class that, surprise, needs a Trade object as well. An elided version of these classes is shown below:
public class Command { public Command(Trade trade, Node node, IView view) { } } public class TradeNode : Node { public TradeNode(Trade trade) { } }
When we request an instance of the Command class using a known Trade object, all of the classes (Command itself, TradeView, and TradeNode) that need a Trade object in their constructor would get the Trade object we specified in …With<Trade>(theTrade)… below:
[Test] public void Explicit_services_are_used_throughout_the_object_graph() { var theTrade = new Trade(); IContainer container = new Container(r => { r.ForRequestedType<IView>().TheDefaultIsConcreteType<TradeView>(); r.ForRequestedType<Node>().TheDefaultIsConcreteType<TradeNode>(); }); Command command = container.With<Trade>(theTrade).GetInstance<Command>(); command.Trade.ShouldBeTheSameAs(theTrade); command.Node.IsType<TradeNode>().Trade.ShouldBeTheSameAs(theTrade); command.View.IsType<TradeView>().Trade.ShouldBeTheSameAs(theTrade); }
If you had more than one IView that displayed a Trade object, you could also do this:
[Test] public void pass_explicit_service_into_all_instances() { // The Container is constructed with 2 instances // of TradeView var container = new Container(r => { r.ForRequestedType<TradeView>() .TheDefaultIsConcreteType<TradeView>() .AddConcreteType<SecuredTradeView>(); }); Trade theTrade = new Trade(); var views = container.With<Trade>(theTrade).GetAllInstances<TradeView>(); views[0].Trade.ShouldBeTheSameAs(theTrade); views[1].Trade.ShouldBeTheSameAs(theTrade); }
and have the known Trade object passed into every instance of TradeView.
I’ll post the other way to do this tonight….