CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

Before you use an IoC tool, some concepts to know first

 
JEREMY’s NOTE:  I’m trying to rewrite the StructureMap documentation today, and I’m going to blog most of it out here as I finish it until Brendan tells me to stop polluting the main feed.  This article is intended to be an introduction to the concepts behind an IoC tool for folks with little or no previous exposure.  Feedback will be very much appreciated.
 
 
From my original release back in June 2004:  StructureMap is a Inversion of Control (IoC) slash Dependency Injection framework that can be used to improve the architectural qualities of an object oriented system by reducing the mechanical costs of good design techniques.  Using StructureMap does not in any way improve your architecture per se, it simply strives to make the mechanics of a good Object Oriented Design cheaper to implement.  Additionally, StructureMap allows you to efficiently exploit a well designed Object Oriented architecture to provide extensibility mechanisms, flexible deployment options, and self validating configuration and deployment.

Over the years a series of concepts and principles have been discovered and developed to describe well-structured Object Oriented systems.  To most effectively use StructureMap, or any other IoC tool for that matter, your system needs to be designed with these principles first:

To sum it all up, well designed Object Oriented systems are composed of many objects that work with each other to accomplish to goals of the system.  We want our systems to be decomposed into cohesive classes that perform a well defined responsibility within the system, rather than monolithic “God” classes that do too much.  A cohesive class will have to be dependent upon other classes to perform services outside of its own tightly defined responsibility.  In IoC speak, we call the collaborating objects dependencies

 

Dependencies

For example, in my current system we have a class called AddressEditController that governs the creation and editing of Address entities in our web based UI.  The AddressEditController needs to validate user input and persist or load data.  Those are two distinct responsibilities, so AddressEditController has dependencies on other objects for these services. 

    public class AddressEditController : Controller

    {

        // AddressEditController uses IValidator to validate user input

        // and IRepository to load and save Address information

        private readonly IValidator _validator;

        private IRepository _repository;

 

    }

So here’s some facts about AddressEditController:

  • AddressEditController depends on IValidator and IRepository 
  • AddressEditController cannot function unless it has both an IValidator and an IRepository
  • From the concepts section above, for best results, the AddressEditController should be loosely coupled to its dependencies by knowing as little about the inner workings of the real IValidator and IRepository
  • The real IRepository is a Gateway into NHibernate. The concrete Repository class cannot be used without its own dependency trail of external configuration, a Singleton to keep track of an expensive resource, and some NHibernate bootstrapping code. 

Just calling a new() constructor on its dependencies isn’t the best design for our AddressEditController.  Creating a concrete Validator class is very possible, but what if we want to selectively replace the implementation of IValidator later?  That’s only somewhat likely, but the dependency on Repository is a much larger concern.  I might have semantic decoupling between AddressEditController and Repository, but if AddressEditController calls new Repository() itself, AddressEditController will not be able to function without all that NHibernate bootstrapping.  I do not want a piece of my user interface to be tightly coupled to the existence of the persistence layer. 

In other scenarios, creating the dependencies may involve more than just calling new() on the dependencies (don’t believe me?  Go try to create an HttpContext object).

AddressEditController is responsible for the workflow around editing Address entities in the UI.  It shouldn’t be concerned with NHibernate configuration and whatnot.  One way to solve this problem is to move the responsibility for building its dependencies to somewhere external to AddressEditController

 

Inversion of Control and Dependency Injection

In many cases, I don’t want my classes to have to be aware of how their dependencies are created or located.  I don’t want controller classes to even care that they’re using an object that is created via Microsoft’s Provider infrastructure, or a Singleton, or needs configuration data.  My class should only know the public interfaces of its dependencies.  I can make that true by applying “Inversion of Control.”  Instead of doing:

        public AddressEditController()

        {

            _validator = new Validator();

            _repository = new Repository();

        }

where AddressEditController calls linearly through to the constructors on Validator and Repository, we can invert the control to make the creator of AddressEditController responsible for building the dependencies and “pushing” them into AddressEditController

    public class AddressEditController : Controller

    {

         private readonly IValidator _validator;

        private IRepository _repository;

 

        public AddressEditController(IValidator validator, IRepository repository)

        {

            _validator = validator;

            _repository = repository;

        }

    }

The code sample above uses a form of Inversion of Control called Dependency Injection to push in the dependencies via a constructor function.  Of course, at some point, something needs to know how to create the entire chain of dependencies and do all of that Dependency Injection.  StructureMap supports a pattern known as Service Locator:

            // Creates an AddressEditController with all of its dependencies

            AddressEditController controller = ObjectFactory.GetInstance<AddressEditController>();

ObjectFactory is a StructureMap class that serves as a well known place to go and find any service that you need.  When the AddressEditController is created and returned by ObjectFactory, it should be completely ready to go.  There’s another important concept to understand before you use StructureMap. 

 

Auto Wiring

Every "real" IoC container supports the concept of "Auto Wiring."  Auto Wiring simply means that StructureMap can figure out dependency chains for you without a lot of explicit configuration.  When you ask for AddressEditController, there is more going on than just AddressEditController and its two dependencies.  The Repository class itself has its own dependencies.

        [DefaultConstructor]

        public Repository(ISessionSource source) : this(source.CreateSession())

        {

 

        }

In turn, the concrete version of ISessionSource above has its own dependencies:

        public SessionSource(IDictionary<string, string> properties, PersistenceModel model)

        {

            _configuration = new Configuration();

            _configuration.AddProperties(properties);

 

            model.Configure(_configuration);

 

            _sessionFactory = _configuration.BuildSessionFactory();

        }

which starts to get interesting because SessionSource needs some information like connection strings that have to come in from Xml configuration: 

<StructureMap MementoStyle="Attribute">

  <DefaultInstance

    PluginType="ShadeTree.DomainModel.ISessionSource,ShadeTree.DomainModel"

    PluggedType="ShadeTree.DomainModel.SessionSource,ShadeTree.DomainModel">

    <properties>

      <Pair Key="connection.provider" Value="NHibernate.Connection.DriverConnectionProvider" />

      <Pair Key="connection.driver_class" Value="NHibernate.Driver.SqlClientDriver" />

      <Pair Key="dialect" Value="NHibernate.Dialect.MsSql2000Dialect" />

      <Pair Key="hibernate.dialect" Value="NHibernate.Dialect.MsSql2000Dialect" />

      <Pair Key="use_outer_join" Value="true" />

      <Pair Key="connection.connection_string" Value="a connection string that I’m certainly not giving out to you!" />

      <Pair Key="show_sql" Value="true" />

    </properties>

  </DefaultInstance>

</StructureMap>

Here’s some of the configuration for the other services that the entire EditAddressController needs:

            ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>();

            ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>().CacheBy(InstanceScope.Hybrid);

            ForRequestedType<PersistenceModel>().TheDefaultIsConcreteType<DovetailPersistenceModel>();

At no point did I specify that EditAddressController needs an IRepository that needs an ISessionSource that needs 2-3 other things, but yet when I call:

            // Creates an AddressEditController with all of its dependencies

            AddressEditController controller = ObjectFactory.GetInstance<AddressEditController>();

StructureMap will construct EditAddressController that had a new instance of Repository that had a new instance of SessionSource that had an IDictionary<string, string> object and a new instance of DovetailPersistenceModel.  I don’t have to explicitly tell StructureMap to do that for me because it uses its “Auto Wiring” feature to examine the dependencies of each concrete class and act accordingly.  StructureMap does need to know what to do with each type of object it encounters.  When it tries to build the Repository class StructureMap sees the constructor argument for ISessionSource on Repository, and knows to build and inject a new SessionSource object (and so on as deep as you need to go).



Comments

Jeremy D. Miller said:

Another note, It'll be published in a wider format, so the code getting cut off won't be quite the same issue

# June 29, 2008 4:42 PM

jdn said:

This is good stuff, very helpful, especially for people like me who are using StructureMap 'in anger' for the first time.

Thanks.

# June 29, 2008 8:35 PM

Jeremy D. Miller said:

@John,

Please feel free to drop me a line if anything is confusing or unclear about the API or in the docs.

# June 29, 2008 8:37 PM

jdn said:

@jdm

Yep.  I'm obviously not starting with the most complicated uses of SM, so I expect the API to lead the way, but will send anything if it isn't obvious.

# June 29, 2008 9:50 PM

Afif said:

Jeremy,

I would be very interested in knowing what are your views on Ninject(another IOC container)? Have you had a chance to look at in any detail? I am fairly across the reasons for using IOC and the benefits it brings, but am yet to dive into a tool, simply because I haven't had a chance to use it at work, and also a bit reluctant before starting to choose one that has the smallest learning curve and complexity from a user's perspective. Going by the tutorials ninject seems pretty decent(read: easy to learn), specially with no 'xml' configuration files.

While I imagine your views will be baised with you authoring StructureMap albeit they will still be very helpful.

- Cheers

# June 29, 2008 9:55 PM

Jeremy D. Miller said:

@Afif,

I purposely avoid looking too deeply at the other IoC tools, so I'm not really the right source.  You can use both Windsor and StructureMap w/o any Xml, so that isn't really unique.  I've put a bit of effort to make StructureMap more accessible for newcomers, but the biggest part of that effort is probably in the form of (unwritten) documentation.

Honestly, they're not that different for the simple things.  Just don't repeat that I said that, okay?

# June 29, 2008 10:35 PM

Reflective Perspective - Chris Alcock » The Morning Brew #125 said:

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #125

# June 30, 2008 3:30 AM

tomdekoning said:

Hi Jeremy,

I will be starting today with StructureMap as well. Will let you know if anything is unclear..

KR,

Tom

# June 30, 2008 5:01 AM

Asa said:

Hi Jeremy,

Forgive my dumb question, but does using an IOC tool mean giving up the New Keyword to initialize objects?

# June 30, 2008 7:03 AM

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# June 30, 2008 7:03 AM

Dew Drop - June 30, 2008 | Alvin Ashcraft's Morning Dew said:

Pingback from  Dew Drop - June 30, 2008 | Alvin Ashcraft's Morning Dew

# June 30, 2008 8:01 AM

tomdekoning said:

Hi Jeremy,

Where can I find the documentation on structuremap? When I look at sourceforge.net/docman there is no documentation available, or am I missing something?

KR,

Tom

# June 30, 2008 9:05 AM

Jeremy D. Miller said:

Tom,

I'm writing it as fast as I can.  There is existing documentation for StructureMap 2.0 at structuremap.sourceforge.net

# June 30, 2008 9:12 AM

tomdekoning said:

Sorry, I don't know how I could have overlooked that one. Thanks!

# June 30, 2008 9:21 AM

Kerry said:

We're still behind the curve a bit on IoC, so I hope a few rather basic questions are tolerable.  I'm not sure if we'll get to use Structure Map per se, but these may help with our general architecture.

The first thing that comes to mind is how does ObjectFactory know when to use an object that has had state modifications as opposed to a new one?  One example I have is a specification we use that compares a base object's (a "Firm.Type") property to that of an object of a different type ("Employee.FirmType").

When a Firm is edited, we need to modify each one of it's employees to make sure the types match.  However, when an employee is modified, we need to make sure of the same thing (because an employee can be removed from the firm by setting Firm.Type to none).

So passing in a stateful firm to the Specification is critical when the specification is originated from a firm modification, but we need a new firm from the database when the employee is modified.

How does IoC handle this?

# June 30, 2008 9:40 AM

Chad Myers said:

@Kerry:  I'm not sure what you're trying to accomplish here. Why should Employee care what exact type of Firm it has? Doesn't that violate the Liskov Substitution Principle?  Employee should have a Firm. It can be any type of class as long as it derives from Firm.  

I don't think this problem has anything to do with IoC, so this may not be the best place to ask this kind of question.

What are you trying to do with the Employee/Firm stuff and how are you using IoC in your project? Maybe that'll help us understand what you're up to.

# June 30, 2008 11:33 AM

Nate Kohari said:

@Afif

Ninject is my framework, so naturally I would suggest you check it out. ;)

However, StructureMap is great, as are other frameworks like Castle Windsor and Autofac, and Jeremy is right in that they are very similar for the simpler cases. However, each has nuances -- for example, Ninject provides context during activation, so the activation process is more programmatic and less of a "map lookup". This lets you do some interesting things depending on state when your instances are being resolved and activated.

I also haven't dug too deeply into StructureMap's internals, so I can't conclusively say either framework is "better". I think it comes down to a matter of taste, and you should try each of the different tools and decide which of them feels right to you.

# June 30, 2008 11:44 AM

RobinClowers said:

Hi Jeremy, thanks for this post, it helped me understand exactly what auto wiring is and how it relates to the service locator pattern.  Another thing I would like to see is some info on the different config options, especially the fluent API.

# June 30, 2008 1:17 PM

Arjan`s World » LINKBLOG for June 30, 2008 said:

Pingback from  Arjan`s World    &raquo; LINKBLOG for June 30, 2008

# June 30, 2008 2:30 PM

Andrei Butnaru's blog said:

Programming links 06.30.2008

# June 30, 2008 2:38 PM

Guy Ellis said:

I haven't used StructureMap (yet) but that was an excellent explanation of IoC and DI - thanks!

# June 30, 2008 3:26 PM

Frank Smith said:

Overall, this is a good article. Just one point... I don't think you are using the word "cohesive" in the correct way. The concept of cohesion at the class level isn't related to whether the class depends on other classes or not.

See also:

javaboutique.internet.com/.../coupcoh

www.developer.com/.../3327121

"A cohesive object is one that cannot easily be broken up into multiple objects. It is an object that has one clear purpose and one clear entity that it represents."

# July 1, 2008 7:44 AM

Jeremy D. Miller said:

@Frank,

I didn't mean to imply that "cohesive" automatically means that a class depends on other classes.  What I meant was that a class that is cohesive will *have to depend on other classes for services outside the scope of its own cohesive responsibilities*

The point I was going for is that classes are not monolithic and interact with each other.

# July 1, 2008 8:10 AM

Kerry said:

@Chad,

Thanks.  It's not the type of firm, it's which firm.  In the one case, the firm has been edited (but not yet persisted) and we're trying to make sure all of its clients are updated with the edited properties (may be a smell there, but that's a requirement at this point).

In the other case, we want to be sure that the client has the same settings as an already persisted firm.

If that's not clear enough, I'll be more than happy to take it offline - I don't want to clutter up these comments with it.

# July 1, 2008 9:37 AM

Chad Myers said:

@Kerry:

Yeah I'd be interested to hear what's going on there. You can email me firstname.lastname@gmail.com (chad.myers...)

# July 1, 2008 10:27 AM

Frank said:

@Jeremy:

I was just attempting to make the point that cohesion and interclass dependency are orthogonal concepts. A cohesive class may or may not have dependencies on other classes. The same is true for a noncohesive class.

Cheers,

Frank

# July 1, 2008 7:36 PM

Sam Gentile Uri address = new Uri("http://localhost:8000/HelloIndigo"); said:

Its about time to clear out the backlog. CLR/.NET/Visual Studio/TDD/ALT.NET Jeremy has a nice piece here

# July 5, 2008 11:33 AM

Jonty said:

How do you deal with the fact that certain assemblies do not have references to other assemblies?

I am calling registries in each assembly like below:

StructureMapConfiguration.AddRegistry(new BusinessLogicLayer.DependencyInjectionRegistry());

Then in my BusinessLogicLayer I have:

protected override void configure() {

ForRequestedType<IBusinessLogicStuff>().TheDefaultIsConcreteType<BusinessLogicStuff>();

StructureMapConfiguration.AddRegistry(new DataAccessLayer.DependencyInjectionRegistry());

       }

Is this the correct approach?

# July 10, 2008 1:58 PM

Brian Johnston said:

@JEREMY’s NOTE:  I’m trying to rewrite the StructureMap documentation today, and I’m going to blog most of it out here as I finish it until Brendan tells me to stop polluting the main feed.  This article is intended to be an introduction to the concepts behind an IoC tool for folks with little or no previous exposure.  *Feedback will be very much appreciated.*

Two things have always been top-most in my mind:

1) A hello-world walk-through - and I mean 'hello-world' - as dumbed down as it can get with every step there (assume your reader/watcher is complete moron with no ability to figure anything out on there own).

The reason being is people like myself, this is what make or breaks our interest.  Naturally I'll have some interest because I've read your stuff for a while, know your a smart guy, and conceptually understand what your doing with the framework and how it can build a better product, but that alone won't sell me.  When I get on the site and start looking at the API docs, I can only read those long pieces of documentation and all the 'getting into the weeds' code when I have a genuine interest in the technology.  A hello world can actually do that for me.  

Taking your examples above...you lost me pretty quickly - first you hit me with a bunch of design principals, some okay for the context, some a little to technical for newbies (# Open Closed Principle, the Single Responsibility Principle, and the Liskov Substitution Principle and # Dependency Inversion Principle) - pretend your talking to management, keep the summary (and don't be afraid to expand upon it!) and just add those links for 'further reading'.  Next you got straight into real world code.  I don't work where you work - so instead of focusing on how the framework can help me I'm sitting here wondering why you have a separate controller for just handling address because we use a controller that covers the entire customer (including addresses)...see what I'm saying? I'm getting lost in the weeds rather than focusing on the benefits of the framework.  I want the real world code, but later, after I got the framework down.

From a hello world I can generally determine (a) is it the right fit for me on the current project or possibly an upcoming one?  (b) is it going to be hard to get other developers to use (c) is it creating more problems than its solving for my current project (d) am I'm going to spend 80% of my time implementing 20% of the project in order to use this framework (e) (if applicable) can I write tests for code that use this?

2)Know your audience - this kills me, I mean it gives me GREAT pains with Rhino Mocks and why my use of it is minimal - never assume your audience has worked with a similar framework or really 'gets' what the framework is doing conceptually and that all you need is API documentation and a sprinkle of examples with a 2 sentance explanation of what's going on.  

Rhino Mocks for example: conceptually I know what mocks are for, the benefits, etc., I've read every piece of documentation on that website, but can I apply that knowledge using RM?  Only after much grief and then my use of it is minimal because it just doesn't 'mesh'.  I don't know how else to describe it...it's cumbersome, kludgey, reminiscent of RPG with that chaining crap, etc...

Now don't get me wrong, I *know* in reality it's very powerful and it's a matter of experience and someday it will flow like water out of my fingertips (as is this framework) - but it's turning that learning curve from a mountain with a 900ft cliff face to a bump in the ground that you could barely roll a ball down; that's the challenge.

That's my two cents...since you asked.

# July 24, 2008 9:32 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

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 previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

Our Sponsors

Free Tech Publications

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP