Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

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.

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 StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Matt

    Jeremy,

    What does the InstanceScope.HybridHttpSession option do exactly?

  • http://creedcultcode.blogspot.com Dale Smith

    Anyone who knows me will tell you I’m all about punctuality. So now that StructureMap 2.0 has been around for a year and a half, I swiped some code from Joshua Flanagan and threw together a sample app:

    http://creedcultcode.blogspot.com/2008/08/boba-fett-greedo-and-structuremap.html

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

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

  • http://haacked.com/ Haacked

    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?

  • http://haacked.com/ Haacked

    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?

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

    Mike,

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


    Get this by going: IService service = ObjectFactory.GetNamedInstance(“Local”);

    http://structuremap.sourceforge.net/Configuration.htm#Instance

  • Mike

    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().TheDefaultIs( Registry.Instance().UsingConcreteType()
    .WithProperty(“host”).EqualTo(“localhost”)
    .WithProperty(“port”).EqualTo(5018)
    );

    in the config file instead of in code.

    Any help would be greatly appreciated.

  • http://codebetter.com/blogs/jeremy.miller jmiller

    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 and GenericValidator to IValidator, 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 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.

  • http://udidahan.weblogs.us Udi Dahan

    Does StructureMap support “generic matching” like I detail here:

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

  • http://codebetter.com/blogs/jeremy.miller jmiller

    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

  • http://www.ayende.com/Blog Ayende Rahien

    * 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

  • http://newisv.blogspot.com/2007/04/great-introduction-to-structuremap-20.html Marko Rangel

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

  • Samuel

    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.

  • http://www.developernotes.com Nick Parker

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