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

Introduction to StructureMap 2.0 (Part 1)

I'm assuming some prior knowledge of Inversion of Control/Dependency Injection tools in this post.  The most exciting addition to StructureMap 2.0 for me is the new Fluent Interface API for programmatic configuration of object composition.  There are two entry points into this functionality:

  1. You can make calls directly to the static StructureMapConfiguration class in some sort of application startup.
  2. Create your own Registry subclass in an assembly that StructureMap.  You will have to direct StructureMap to scan the assembly containing your custom Registry class.  I meant the Registry class to be an easy way to segregate the configuration into more manageable chunks and to make the configuration of composite applications easier.  More on this in a later post.

 

QuickStart

Let's jump right in.  The simplest possible usage of StructureMap is to define the default concrete type to use for a given abstraction.  In this case, I have an interface called IService, and the default instance I'd like to use within the application is a concrete implementation called LocalService

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

            StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;

 

            StructureMapConfiguration.BuildInstancesOf<IService>()

                .TheDefaultIsConcreteType<LocalService>();

Before I configured the IService interface, I shut off the usage of the default StructureMap.config file so StructureMap doesn't whine at you if that file doesn't exist.  Now, you're completely ready to request IService instances from ObjectFactory like this:

            IService service = ObjectFactory.GetInstance<IService>();

Scoping

That's the simplest possible and most common usage of StructureMap, but there are plenty more usages of Dependency Injection supported by StructureMap.  Let's take another step and control the scoping of the IService instances.  By default, StructureMap builds a brand new instance for each request to GetInstance<T>(), but that behavior can be overridden.  For example, when you use an ORM like NHibernate you typically want to share the NHibernate ISession across all classes executing in the current thread or HttpContext.  In that case a "PerRequest" instance isn't desirable, so I'm going to make the scope of IService be ThreadLocal.  Anytime an IService is requested, StructureMap is going to first check if there is an existing instance cached in ThreadLocalStorage and return that instance if it exists.  Otherwise, it will build a new instance and cache the new instance on ThreadLocalStorage.

            StructureMapConfiguration.BuildInstancesOf<IService>()

                .TheDefaultIsConcreteType<LocalService>()

                .CacheBy(InstanceScope.ThreadLocal);

Notice the bolded part of the code above.  Other options for scoping available today are a Singleton, HttpContext, and a Hybrid model that looks for a current HttpContext first and defaults back to ThreadLocalStorage if the code isn't running inside ASP.Net.  Because it's so common in usage, there is a convenience method for marking instances as a Singleton.

            StructureMapConfiguration.BuildInstancesOf<IService>()

                .TheDefaultIsConcreteType<LocalService>()

                .AsSingletons();

Primitive Constructor Arguments

Connecting abstract types to concrete types is the most common usage of a Dependency Injection tool, but many concrete types are going to need additional information like connection strings, server names, filenames, and any other number of configuration items.  StructureMap has always supported that need, and it's actually how I generally do configuration.  Let's introduce a new type of IService that needs a couple of constructor arguments:

    public class RemoteService : IService, ICloneable

    {

        public RemoteService(string host, int port)

        {

            _host = host;

            _port = port;

        }

    }

RemoteService above exposes a pair of constructor arguments to connect to a remote server.  Let's say that you're perfectly fine with just embedding the server name and port into your code.  The configuration of RemoteService would look like this:

            StructureMapConfiguration.BuildInstancesOf<IService>().TheDefaultIs(

                Registry.Instance<IService>().UsingConcreteType<RemoteService>()

                    .WithProperty("host").EqualTo("localhost")

                    .WithProperty("port").EqualTo(5018)

                );

In reality, you're going to pull most of this kind of information from some sort of configuration.  I've added a convenience method to the new Fluent Interface to grab information from the AppSettings in the application config file.

            StructureMapConfiguration.BuildInstancesOf<IService>().TheDefaultIs(

                Registry.Instance<IService>().UsingConcreteType<RemoteService>()

                    .WithProperty("host").EqualToAppSetting("SERVER-HOST")

                    .WithProperty("port").EqualToAppSetting("SERVER-PORT")

                );

There are a lot of other tricks and traps for managing configuration over multiple environments, but I'm going to leave that for it's own post.  What I will say is that I've found that doing configuration in this way is very beneficial.  By just injecting information through constructor arguments your configuration reflects your code instead of the other way around.  Your code is now perfectly able to run without any hard coupling to the existence of a certain configuration strategy.  That decoupling leads to code that's easier to test and promotes better opportunities for reuse.

I want to build the instance, you just deliver it!

This is all new for version 2.0.  You might just want to create the objects yourself for some reason or another and just direct StructureMap to deliver your instance on calls to ObjectFactory.GetInstance<T>().  That can be done in a couple ways like these examples shown below:

            // Register a prebuild instance, this exact instance will be returned on

            // any request to ObjectFactory.GetInstance<IService>()

            StructureMapConfiguration.BuildInstancesOf<IService>().TheDefaultIs(

                Registry.Object<IService>(new LocalService())

                );

 

            // Register a prebuild instance, a clone of this instance will be returned on

            // any request to ObjectFactory.GetInstance<IService>().  The concrete type

            // will have to implement ICloneable for this to work

            RemoteService service = buildService();

            StructureMapConfiguration.BuildInstancesOf<IService>().TheDefaultIs(

                Registry.Prototype<IService>(service)

                );

 

 

There will be more.  Next time I'll take a look at auto wiring, configuring child dependencies, and scanning assemblies for classic StructureMap attributes.



Comments

Nick Parker said:

Does StructureMap support defining custom scoping?  With WindsorContainer a custom lifestyle for a component (http://castleproject.org/container/documentation/trunk/usersguide/lifestyles.html).

# April 9, 2007 11:53 AM

Samuel said:

Are you going to post the source code for StructureMap v2.0 sometime in the near future?  I'd be particularly interested in looking at some of the underlying implementation of this great tool.

# April 9, 2007 11:58 AM

Marko Rangel said:

This really does help me get a better understanding on how to use StructureMap.  It seemed to me recently that I could not find any good examples on how to use StructureMap in a real word application as all the examples I found either needed a lot of prior knowledge on how to use such a tool, or were more advanced examples (perhaps I was looking for examples in the wrong places).

# April 9, 2007 12:10 PM

Ayende Rahien said:

* In that case a "PerRequest" instance isn't desirable,

PerRequest is often used to denote PerWebRequest, not per call to GetInstance, the term that I have heard used to decribe such instances is transient

# April 9, 2007 12:37 PM

Jeremy D. Miller said:

Nick,

Yes you can, I just need to document it a little bit. You'd have to go to the xml configuration at the moment.  I thought about adding something to the Fluent interface for that, but didn't get around to it.  It works basically the exact same way.  You could also use it to intercept requests for a named instance and return a different one. That might be worth a post.

Samuel,

I'll add a download, but you can grab it out of SVN from sourceforge.  

svn co https://structuremap.svn.sourceforge.net/svnroot/structuremap/trunk structuremap

# April 9, 2007 12:39 PM

Udi Dahan said:

Does StructureMap support "generic matching" like I detail here:

http://udidahan.weblogs.us/2007/04/09/advanced-object-creation-with-dependency-injection

# April 9, 2007 11:28 PM

Jeremy D. Miller said:

Udi,

Not quite the scenario you describe no.  I could think of workarounds and I know how I'd code that feature.  

You could do something like have the Xml configuration to define the abstract types and assemblies you care about.  When StructureMap scans the assemblies on its first request for an instance, it looks for concrete classes with a [Pluggable("some name")] attribute and decides where these concrete classes could plug into.  That logic would attach CustomValidator<T> and GenericValidator<T> to IValidator<T>, but not the more specific types.

In StructureMap everything revolves around the abstract type you're requesting.  There isn't anything that would check across "PluginType's" to do what you're looking for.

One thing I do have coming up on my project is the need to do something like:

Get the right IPresenter<T> where T : Trade by just passing in the type of a Trade object.  I'll probably extend StructureMap for that case which might be a workaround as well for yours I suppose.

# April 10, 2007 5:57 AM

Mike said:

I am new to StructureMap. At this point I have used the PluginFamily and Plugin StructureMap.config tags fairly successfully. However, I have not figured out what the Instance tags are for, nor have I been able to use them successfully.

I would also like to see an example of how to do the following:

StructureMapConfiguration.BuildInstancesOf<IService>().TheDefaultIs(                Registry.Instance<IService>().UsingConcreteType<RemoteService>()

                   .WithProperty("host").EqualTo("localhost")

                   .WithProperty("port").EqualTo(5018)

               );

in the config file instead of in code.

Any help would be greatly appreciated.

# August 20, 2007 3:57 PM

Jeremy D. Miller said:

Mike,

Try this, and yell at me if this doesn't help.

<!-- The MementoStyle attribute matters! -->

<StructureMap MementoStyle="Attribute">

<PluginFamily PluginType="assembly qualified name of IService">

   <Instance Key="Local"  PluggedType="assembly qualified name of concrete class" host="localhost" port="5018" />

</PluginFamily>

</StructureMap>

Get this by going:  IService service = ObjectFactory.GetNamedInstance<IService>("Local");

structuremap.sourceforge.net/Configuration.htm

# August 20, 2007 4:18 PM

Haacked said:

One question, by doing this, I've now added a concrete dependency to a specific service. If I want to swap out that service with another at runtime, I couldn't use this approach. Not that that is a big problem. I think it just means the use cases are different. If I want to use this as a plugin model, I'd use the config file. If I simply want DI and IOC, I could use this mode *or* the config model.

Is that correct or am I missing something?

# December 8, 2007 5:37 PM

Haacked said:

One question, by doing this, I've now added a concrete dependency to a specific service. If I want to swap out that service with another at runtime, I couldn't use this approach. Not that that is a big problem. I think it just means the use cases are different. If I want to use this as a plugin model, I'd use the config file. If I simply want DI and IOC, I could use this mode *or* the config model.

Is that correct or am I missing something?

# December 8, 2007 5:37 PM

Jeremy D. Miller said:

@Phil,

I'm not understanding you here.  You should be able to swap almost anything out at runtime, regardless of how the configuration was done.  The Fluent Interface & xml both arrive at the exact same point.  You can also mix and match the two.  

# December 10, 2007 8:31 AM

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!

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