Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0

It took long enough, and I've had a pretty good stream of people asking for this, so here it is:  StructureMap 2.0 is finally ready for download on Sourceforge.  My goals with the release were to fully support Generic types, to create a much smoother user experience, and improve the ease of use.  If you're not familiar with the twin concepts of Inversion of Control or Dependency Injection, there are some links at the bottom for background information.

I started work on StructureMap in the fall of 2002 as an attempt to learn .Net by writing the world's ultimate O/R Mapper.  Unsurprisingly, that didn't work out very well, and I stopped my work on the O/R mapping shortly after ObjectSpaces was announced (sic).  In the early months of 2004 I was working for ThoughtWorks, and PicoContainer in Java was all the rage on our internal boards.  I picked back up StructureMap, harvested the overly elaborate configuration subsystem I had been building, and in far too late nights in a terminal in Chicago O'Hare waiting for my delayed flight home, turned StructureMap into a tool for doing Dependency Injection and Service Location in .Net.  StructureMap was first used in a production system in June of 2004, and I've used it since on all but one short project.  This is the 4th release.

Here's just a taste of the new capabilities in StructureMap 2.0, with a lot more to follow over the next couple weeks.  If you've been intrigued by ObjectBuilder's potential but put off by its limitations, or you're completely aggravated by the string keys of a certain competing tool, check out StructureMap for a smoother experience and much more power.

Generics

The biggest new feature is full support for doing dependency injection and service location with generic types, including n-deep auto wiring.  Say you have two classes and interfaces (elided) like this: 

    public interface IDataService<T>

    {

        T Load(int id);

        void Save(T target);

    }

 

    public class DataService<T> : IDataService<T>

    {

    }

 

    public interface IRepository<T>

    {

        T Find(int id);

        void Save(T target);

    }

 

    public class Repository<T> : IRepository<T>

    {

        private readonly IDataService<T> _service;

 

        // Repository requires an instance of IDataService

        public Repository(IDataService<T> service)

        {

            _service = service;

        }

    }

The configuration for these generic types is:

<StructureMap>

  <DefaultInstance

    PluginType="StructureMap.Testing.IDataService`1, StructureMap.Testing"

    PluggedType="StructureMap.Testing.DataService`1, StructureMap.Testing" />

 

  <DefaultInstance

    PluginType="StructureMap.Testing.IRepository`1, StructureMap.Testing"

    PluggedType="StructureMap.Testing.Repository`1, StructureMap.Testing" />

</StructureMap>

In this configuration we've just specified the default concrete types to be used for both IDataService<T> and IRepository<T>.  If either class had any primitive constructor arguments like database connection strings, you would also have to configure property values for these values.  Note the class name "Repository`1."  We're specifically setting up the templated type in memory.  StructureMap will spot that this class is a templated type and keep back a list of internal InstanceFactory objects for each templated class. In usage, you would retrieve a Repository like this:

            IRepository<Invoice> repository =

                ObjectFactory.GetInstance<IRepository<Invoice>>();

When this line is called for the first time, StructureMap takes the cached InstanceFactory for IRepository<>, and uses that as a prototype to create and attach a new InstanceFactory for IRepository. Please note that StructureMap supports "auto wiring." In this example, StructureMap knows the default instance to return for a type of IDataService. When the default IRepository is requested, StructureMap is going to return a concrete Repository object. Looking at the constructor for Repository there is an argument for an IDataService object. Unless directed otherwise, StructureMap will push in the default IDataService into that constructor argument.

P.S.  Am I the only person that thinks sprinkling generics all over makes for ugly code?

Easier Configuration

One of the goals for this release was to make the Xml configuration easier to use and reduce the "signal to noise ratio."  The underlying model of PluginFamily/Plugin/InstanceMemento is completely unchanged, but I've strived to hide more of the complexity in the configuration files.  Say you only need to define the default concrete type for a given interface, and maybe configure a couple of constructor arguments along the way.  Here's a sample of new capabilities in the configuration schema.

<StructureMap MementoStyle="Attribute">

  <DefaultInstance

    PluginType="StructureMap.Testing.Widget.IWidget,StructureMap.Testing.Widget"

    PluggedType="StructureMap.Testing.Widget.ColorWidget,StructureMap.Testing.Widget"

    Color="Red" /> 

 

  <DefaultInstance

    PluginType="StructureMap.Testing.Widget.Rule,StructureMap.Testing.Widget"

    PluggedType="StructureMap.Testing.Widget.ColorRule,StructureMap.Testing.Widget"

    Color="Blue"

    Scope="Singleton"

    Name="TheBlueOne"/> 

</StructureMap>

First, in the <StructureMap> node you'll see a new attribute called MementoStyle.  In the last release I introduced a new terse, attribute normalized mode to configure instance properties.  By setting MementoStyle to "Attribute," I'm directing StructureMap to use the attribute normalized style throughout.  The new <DefaultInstance> node is a shorthand way just to specify the default instance of a targeted PluginType in one node.  In the <DefaultInstance> nodes above, I'm specifying the targeted PluginType (IWidget), the actual concrete class to use (ColorWidget : IWidget), and setting the one constructor argument "Color."  I can also specify the instance to be scoped as a singleton or another scoping choice.

Long time StructureMap users will notice that there are no <Assembly> nodes or <PluginFamily> nodes.  In this example they are unnecessary.

Flexible Configuration

Besides generics, the next most common request has been for more flexible configuration choices besides the StructureMap.config file.  And now that there is a somewhat justifiable backlash against programming in Xml, what if you don't want to use Xml configuration at all?  There's a new sheriff in town, the StructureMapConfiguration class.  In your application startup, make calls to the static methods on StructureMapConfiguration to direct StructureMap how and where to get its configuration.

            // You know what, I don't want to use the StructureMap.config file

            StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;

 

            // I want to pull configuration from these 3 files instead

            StructureMapConfiguration.IncludeConfigurationFromFile("Component1.config");

            StructureMapConfiguration.IncludeConfigurationFromFile("Component2.config");

            StructureMapConfiguration.IncludeConfigurationFromFile("Component3.config");

 

            // On startup, I want to check the configuration for any problems

            // and run environment tests

            StructureMapConfiguration.OnStartUp()

                .FailOnException()

                .WriteProblemsTo("problems.txt");

 

Programmatic Configuration with a Fluent Interface

StructureMap 2.0 includes a new Fluent Interface API as a programmatic mechanism for adding PluginFamily's and Plugin's.  For simpler systems without a lot of variable configuration, or for the Xml averse, the new API may be the best way to go.  The Fluent Interface is a superset of the configuration possible with attributes, and has the advantages of keeping classes clean of StructureMap intrusion and keeping the StructureMap configuration relatively contained in a cohesive area instead of being scattered throughout the code.

                              // Simply set up StructureMap to return a StubbedGateway class whenever IGateway is requested

            StructureMapConfiguration.BuildInstancesOf<IGateway>().TheDefaultIsConcreteType<StubbedGateway>();

 

            // Instead, set the default IGateway to the real thing, and also specify the host and port

            // number.  Pull the host and port number from AppSettings

            StructureMapConfiguration.BuildInstancesOf<IGateway>()

                .TheDefaultIs(

                    Registry.Instance<IGateway>().UsingConcreteType<ServerGateway>()

                    .WithProperty("host").EqualToAppSetting("ServerName")

                    .WithProperty("port").EqualToAppSetting("Port")

                );

 

 

 

Information on Inversion of Control and Dependency Injection

 

Upcoming Tutorials and Samples

Watch my blog in the upcoming weeks for a stream of little tutorials and samples of using StructureMap, including some functionality that I don't believe is offered by other tools.  The subjects I'm thinking about writing about are:

  • Why use a Dependency Injection tool at all?
  • The new Fluent Interface API for programmatic configuration
  • Lessons Learned for building a Fluent Interface
  • Using StructureMap with zero Xml
  • An experience report on applying the DRY principle to StructureMap's configuration schema
  • Configuration options for composite applications
  • Configuration Management support in StructureMap
  • Diagnostics and Environment test support in StructureMap
  • Auto wiring support
  • Best practices for using StructureMap in tests to inject mocks and stubs
  • An example of using StructureMap to create a pluggable Chain of Responsibility
  • User and machine specific configuration
  • Dependency Injection of ASP.Net UserControl's

Please feel free to send any suggestions or comments to me.

 


Posted 04-02-2007 10:27 AM by Jeremy D. Miller
Filed under:

[Advertisement]

Comments

Ayende Rahien wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-02-2007 2:15 PM

> P.S.  Am I the only person that thinks sprinkling generics all over makes for ugly code?

Absolutely not.

Congrationaltions

David Hayden wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-02-2007 5:34 PM

Is it possible to pass StructureMap an object instance and have it inject dependencies on the properties based on configuration information? In this case, I don't want StructureMap to instantiate the type, just inject dependencies.

Seems like this would be useful in cases where I don't have control over object instantiation but do have control over adding properties to the class to specify dependencies.

This is in reference to the View-Presenter Post I just mentioned where I don't have control over creating the System.Web.UI.Page Class but I can intercept it before the page life cycle and inject depdendencies into it:

http://codebetter.com/blogs/david.hayden/archive/2007/04/01/Wire_2D00_Up-View_2D00_Presenter-Pattern-Like-Web-Client-Software-Factory-_2D00_-Castle-Windsor-for-Dependency-Injection.aspx

As you know, StructureMap was my introduction to DI and really opened my eyes. Great job on providing such a valuable tool to the community.

Jeremy D. Miller wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-02-2007 7:44 PM

David,

Yes, but I've never really used it much:

Something something = ObjectFactory.FillDependencies<Something>();

All of the dependent arguments to the constructor function need to be configured in StructureMap, and there cannot be any primitive arguments in the constructor.

You could also use setters by decorating them with [Setter], but I think setter injection is an abomination about 75% of the time.

Thanks for the comment,

Jeremy

Richard LOPES wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-02-2007 10:17 PM

It looks very good.

I can't wait to try it myself.

Jens Winter wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-03-2007 4:02 AM

Congratulations, Jeremy!

Thanks for your great work.

inoodle wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-03-2007 5:35 AM

Hi Jeremy,

I'm liking the sound of this release, especially the ability to use programatic configuration instead of xml files.

Can you give a brief overview of the UserControl injection you mention as I'd like to support it within PoCoRail (http://intrepidnoodle.com/blog/show/8.aspx).

Cheers

Aaron.

Jeremy wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-03-2007 8:36 AM

Will do.  I'll write it up on the train ride home tonight Aaron.

Jeremy

Rinat Abdullin wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-03-2007 5:18 PM

I'm enjoying studying StructureMap 2.0 right now. Thank you for developing it. With this library the road to crossplatform SmartClients seems to be much shorter.

Right now it seems that the default MockInstanceFactory is hardcoded into ObjectBuilder. Is there some way to replace it with the factory for NMock2 without recompiling the SM?

Jeremy D. Miller wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-03-2007 8:15 PM

Rinat,

Just use the ObjectFactory.InjectStub<T>(T something) method to achieve the same goal.  The "Mock" method with NMock just wasn't a good move on my part.

Jeremy

Rinat Abdullin wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-04-2007 4:09 AM

Jeremy,

Thank you for prompt response.

Tried this one last night. Mock object gets hit by Plugin.CanBeCast inside "InjectStub": 'Cannot "Stub" type with an object of type NMock2.Mockery+MockObject'.

Is there any other way to squeeze in Mocking factory and the the object through those internal checks?

I believe "Mock" is a good one (loosely coupled with specific mocking library), since the majority tends to mock-n-test their plugins after all.

Rinat

Console.Write(this.Opinion) wrote Resumo da semana - 09/04/07
on 04-09-2007 12:32 PM

Processos e Agile Ivar Jacobson publicou um artigo com sérias críticas aos processos que dominam o desenvolvimento

Anthony Bouch wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-17-2007 7:32 AM

Hi Jeremy

I've just begun to look at the docs... am trying to find the best 'entry point' into learning about the StructureMap framework.  Have also checked-out the source from SVN on SourceForge. The solution is looking for a Web project at D:\StructureMap\StructureMapTest which I don't think is part of trunk - not sure here.

Looking forward to your upcoming tutorials. Inlcuded in these, would it be possible for you to post a couple of newbie pointers on getting started with StructureMap? (Maybe aimed at those of us who are ok with designing components by interface, but new to DI?)

Tony

Anthony Bouch wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 04-17-2007 11:16 AM

Apologies for the above post Jeremy - have just seen 'Introduction to StructureMap 2.0 (Part 1)' - that's as good a place to start as any :-)

58bits - Tech wrote Application Block Software Factory - Sample App
on 07-03-2007 5:08 PM
Jeremy Wiebe wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 11-02-2007 3:31 PM

Is ObjectFactory.InjectStub() an unfinished implementation?  I'm attempting to use it but it's throwing an exception on me (208).  I've searched the StructureMap source and found it's only used in two unit tests, but these are [Ignore]'d.  When I un-[Ignore] them they fail with the exact same exception.  

Googling around the net it looks like some folks are using it successfully (Jeffrey Palermo, for one), but mimicking exactly what he does hasn't solved the problem.   I know you aren't a "One Stop Support Shop" (TM), but any ideas would be greatly appreciated.  :-)

Jeremy D. Miller wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 11-02-2007 7:03 PM

Jeremy,

I use that method on a nearly daily basis.  Is the type that you're trying to inject already registered with StructureMap?

If you're trying to do:

ObjectFactory.InjectStub<IService>(new SomeKindOfStub());

StructureMap would have to be configured to build IService objects.

StructureMapConfiguration.BuildInstancesOf<IService>() or the equivalent in the Xml file

From the troubleshooting page, the 208 error is:

Requested type {0} is not configured in StructureMap

A call was made to ObjectFactory to fetch an instance of a type not recognized by StructureMap.  This can also occur when a parameter type of a requested instance is not recognized by StructureMap.  In order for StructureMap to be able to construct configurations of a concrete class, all types in the constructor function must be configured under StructureMap.

Jeremy Wiebe wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 11-07-2007 4:31 PM

As is the case so often when I ask questions, it appears I've stuck my foot in my mouth and talked too soon.  I got the InjectStub() call working now by calling InjectStub() right in my unit test.  The only thing I can think that may have caused the problem is that I was using InjectStub() in the [TestInitialize] method of my unit test as well as using TestDriven.NET.  

I just tried moving the InjectStub() call back into the [TestInitialize] method and it's still working fine.. go figure.  The only thing I can think is that I made a call at one point before I had things configured correctly and possibly StructureMap was left in a misconfigured state (inside of the test runner app that TD.NET uses).

Thanks for your help and for StructureMap!  I'm really starting to like this DI and IoC stuff.

Jeremy D. Miller wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 11-07-2007 9:23 PM

anything for another Jeremy

Jeff Doolittle wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 09-23-2008 5:01 PM

I've been using StructureMap Registry classes and the Fluent Interface for a while.  I've got all of my configuration out of .config files and into registry classes.  I hit a situation where I needed to build up a type with a generic type parameter and I found this post.  But this post explains how to accomplish this goal using a config file, which I really did not want to do.  For any one else who wants to use the FI to build up types with generic parameters, this is what I came up with and it works great.

/* code */

Type abstractManager = typeof(IManager<object>).GetGenericTypeDefinition();

Type concreteManager = typeof(Manager<object>).GetGenericTypeDefinition();

ForRequestedType(abstractManager).TheDefaultIsConcreteType(concreteManager );

/* end code */

Hope this helps someone else.

--Jeff

Jeremy D. Miller wrote re: StructureMap 2.0 is Released! Inversion of Control and Dependency Injection for .Net 2.0
on 09-24-2008 9:38 AM

@Jeff,

You could just do:

ForRequestedType( typeof(IManager<>) ).TheDefaultIsConcreteType( typeof(Manager<>) );

Add a Comment

(required)  
(optional)
(required)  
Remember Me?