Total votes: 1
Category: Design Patterns
Print: Print Article
Please login to rate or to leave a comment.
Published: 09 Jun 2009
Have you heard of StructureMap, generally know what it’s for, and want to know how to get started quickly with it? This article will help you achieve all that and give you a few pointers on how to use some of the more intermediate and advanced features!
StructureMap is a type of tool known as an “Inversion of Control Container” (or IoC container for short). It makes managing the complexity of designing software using the “Dependency Inversion Principle” (DIP) easier.
StructureMap, and other IoC container tools like it, solve a particular type of problem when using a particular type of design philosophy in your applications. If you haven’t heard of, or aren’t familiar with the concepts of DIP, IoC, or “Dependency Injection” then this article is not the best place to start. You should first seek out more information on these concepts before proceeding. This article assumes you are already familiar with these terms and are wishing to begin applying them in your application design.
StructureMap is not the only IoC container, so you may wish to check out some of the other popular IoC containers before settling on one for your project. Each container has strengths and weaknesses. In my opinion, StructureMap offers the most flexible and easiest configuration as well as a comprehensive set of advanced features that suit the way I design my systems. Each of the other containers has particular features that are superior to StructureMap, but I think StructureMap is the most well-rounded and easiest to use of the bunch so it’s my weapon of choice.
How do I get started?
Getting started with StructureMap is easy. First, let me drop some links on you so you have some reference material to look through:
To get started, first download the latest release (at the time of this writing, it is version 2.5.3). Unzip the release to a folder and copy the DLL and PDB files to your project directory. Next, add a reference to StructureMap.dll from your Visual Studio project. It’s that simple!
The two most basic concepts you need to understand about StructureMap (or any IoC container for that matter) are: Configuration and Retrieval. That is: Telling StructureMap how your objects’ dependencies map together and finally retrieving your objects from StructureMap’s ObjectFactory.
Before we go too far, let me give you a basic example of how to use StructureMap once it’s already configured (I’ll show you how to configure it in just a little bit). Imagine you had a service called UrlResolver that had an interface abstraction of IUrlResolver. You don’t want your code depending directly upon UrlResolver, you want your code dependent upon IUrlResolver. Let’s say you’ve already configured StructureMap that for any request of IUrlResolver, an instance of UrlResolver comes out. This way your code depends upon the abstraction of IUrlResolver and not directly upon the concrete type UrlResolver. In a place in your code where you needed a url resolver, you might call StructureMap like this:
The variable “resolver” will then actually be of the underlying type UrlResolver. Later, if you develop a different type of UrlResolver (for example, VirtualPathUrlResolver), you would simply have to change your StructureMap configuration and the rest of your app will compile and run without heavy modification.
To initialize and configure StructureMap to produce things like UrlResolver, start with the ObjectFactory.Initialize method. This method follows the “nested closure” pattern in that you must provide it with an Action<T> lambda function to configure ObjectFactory. Consider this simple example which instructs StructureMap to produce our UrlResolver for all requests of IUrlResolver:
A good place to put this call would be in your
Application_Start event in your Global.asax file (for ASP.NET) or in your
void main() method in a Console or Windows application.
One more basic concept you should be aware of is “Autowiring.” Generally speaking, you should avoid calling
ObjectFactory.GetInstance<T>. This technique is “Service Location” and, while not completely unavoidable, you should minimize its use in your app. The preferred way of using StructureMap is to let it automatically wire up your object dependency graphs. To do this, have a non-default constructor in your concrete types that takes an abstraction of another service. For example, let’s say that UrlResolver depended upon another service abstraction called IConfigurationService. The code for UrlResolver might look like this:
Listing 1: UrlResolver concrete class with a dependency upon IConfigurationService abstraction
Let’s also say that IConfigurationService has a concrete implementation called “WebConfigConfigurationService”. Your ObjectFactory initialization would then look like this:
Listing 2: ObjectFactory Initialization with two services
Notice that we haven’t actually told StructureMap that UrlResolver depends upon IConfigurationService. We’ve simply made StructureMap aware that these two services exist. After
Initialize() is called, StructureMap will recognize that the concrete UrlResolver depends upon IConfigurationService. It will then check to see if it has one of those configured (which it does).
When you next call GetInstance for IUrlResolver, StructureMap will remember that IUrlResolver is mapped to UrlResolver. It’ll realize it needs to get an IConfigurationService in order to call “new” on UrlResolver. It’ll then realize it needs to “new” up a new instance of WebConfigConfigurationService and then pass that into the constructor of UrlResolver and, finally, return the instance of UrlResolver.
This concept of automatically wiring up the dependency graph is known as “autowiring” and is an important concept you will need to remember when using StructureMap.
Intermediate Level Concepts
StructureMap, by default, will “new” up a new instance of the concrete type every time you request one from it. You can, on a service-by-service basis configure how StructureMap controls the lifecycle of the object. It supports 3 primary modes: Per-request (default, “new” one up every time), Hybrid (once per thread or ASP.NET request if you’re in a web application), and Singleton (one and only one object per app domain). You can control this by using the
CacheBy method after
ForRequestedType. For example:
In larger projects, there are simply too many services to list in the Initialize call to be manageable. StructureMap solves this by allowing you to segregate configuration of services into “Registry” classes. These “Registry” classes can live in separate assemblies, namespaces, etc. This helps to keep the registration of services manageable and organized. To create a “Registry”, simply create a class that derives from the StructureMap.Configuration.DSL.Registry class (note: NOT the Microsoft.Win32.Registry class). Give your new Registry class a default (parameterless) constructor and then begin calling the same methods as you would in the
Initialize() method nested closure. Consider the following example:
Listing 3: An example of a StructureMap Registry class for distributed configuration
In order for StructureMap to use these registries, you must instruct StructureMap where to look for any potential Registry classes. Do this using the
ObjectFactory.Initialize call. For example:
Note how Initialize no longer contains references directly to services, but instead a reference to the Registry. StructureMap also supports scanning for Registries (rather than explicit configuration). To do this, use the
Scan method in the
Scan() is itself a nested closure method just like Initialize. Scan has many options for finding and filtering the assemblies, namespaces, and types you with StructureMap to consider. The following example shows off a few of these options:
Listing 4: ObjectFactory Initialization with advanced type scanning
In this example, StructureMap will consider all types in the calling assembly (your assembly), all types in the assembly in which ISomeService is defined, likewise with the assembly containing IAnotherSerivce. It also tells StructureMap to ignore all types in the namespace in which ISpecialService belongs.
This article has covered the basics about how to get StructureMap, how to get more information, as well as a quick tutorial of how to start coding with StructurMap. There’s much more depth to StructureMap that is beyond to scope of this “Introduction” article. I hope you check out StructureMap, read the docs, and post to the mailing list with any further questions.
Chad Myers is a senior .NET software developer specializing in enterprise software designs and architectures. He has over 10 years of software development experience and a proven track record of Agile, test-driven project leadership using both Microsoft and open source tools. He is community leader...
View complete profile here.
Please login to rate or to leave a comment.