Using StructureMap 2.5 to inject your Entity objects into Services

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….

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.codinginstinct.com Torkel

    This is a really useful feature, I discovered it (and the need for it) a while ago in Castle Windsor.

  • Jonathan

    When you refer to a “service”, you’re talking about an “Application Service”, right? Per my reading of Evan’s DDD a “Domain Service” is just as much a part of the domain as anything else and can be called from within the domain “core”.

    Case in point: Suppose you had a really complicated interest calculation mechanism in your LoanAccount entity and you wanted to use the same mechanism in your InterestAccount entity, wouldn’t it make sense to inject the service into both in order to “stay DRY”.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Jonathon,

    I was thinking much more in general than DDD in terms of “anything you would not want to new() up directly.:

    Not that you could have possibly known this, but the staggering amount of jargon in DDD is a huge pet peeve of mine.

    “Domain Service” vs “Application Service” might have some useful differentiation, but the jargon still bugs me.

    “Case in point: Suppose you had a really complicated interest calculation mechanism in your LoanAccount entity and you wanted to use the same mechanism in your InterestAccount entity, wouldn’t it make sense to inject the service into both in order to “stay DRY”.”

    I wouldn’t bother with SM for this kind of thing. Just pass the LoanAccount and InterestAccount into the domain service as it’s invoked is my bet.

  • http://davidhayden.com/blog/dave/ David Hayden

    Jeremy,

    Has 2.5 been released yet? I keep seeing reference to 2.5 but only see 2.4.9 for download. Just want to make sure I am not using old bits. Hopefully 2.4.9 is production deployable because deployed she is :)

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @David,

    2.5 is not yet released. Jimmy Bogard has labeled it the Duke Nukem Forever release.

    I’ve got to do more docs and clean up the API a touch.

    There will be very minor API changes from 2.4.9 to 2.5 in the registration

  • http://davidhayden.com/blog/dave/ David Hayden

    Thanks for the info, Jeremy!

    Looking forward to the final release.