Home / StructureMap – A Gentle Quickstart

StructureMap – A Gentle Quickstart

The most general question I get with StructureMap is “how do I get started?”  I’d recommend that you first get comfortable with some concepts and the basic patterns of Dependency Injection and Inversion of Control.  Assuming that you’re already familiar with those concepts, or you’d really rather skip the pedantry and jump right into concrete code, the first thing to do is go download StructureMap and jump into usage (then come back to the patterns and pedantry).

Next Prev

Salient Facts

  • The latest release is available for download on SourceForge at http://sourceforge.net/projects/structuremap
    • The only DLL that you need for doing basic Service Locator and/or Dependency Injection is the StructureMap.DLL file.
  • There is a google group for StructureMap support at http://groups.google.com/group/structuremap-users?hl=en
  • StructureMap is released under the Apache 2.0 license, meaning that you can use it in any application or even modify the source in any way you see fit without restriction.
  • StructureMap is actually the oldest IoC tool for .Net, with the first production release coming in June of 2004
  • The source code is accessible here via Subversion in case you’re curious.  No credentials are required to access the source code.
  • Right now, StructureMap 2.5 will run on .Net 3.5 only.  I will most likely NOT be backporting the new version to 2.0 because of extensive usage of 3.5 features like Expressions
  • StructureMap 2.5 will run in medium trust on .Net 3.5 – but please post any problems that you do find with medium trust.

The Simplest Possible Usage of StructureMap

Your interaction with StructureMap is going to mostly consist of two activities:

  1. Asking StructureMap for an instance of a service or dependency (the easy part)
  2. Registering “what” and “how” StructureMap should build or find those requested services (the tedious part, but it’s gotten much better over the years)

In our system we use a service called “IValidator” to exercise validation rules on our domain model objects.  By default, we want any consumer of the IValidator interface to use the concrete class named Validator.  Since we use StructureMap for resolving dependencies and services, we need to first tell StructureMap to use Validator anytime somebody asks for an IValidator.  You configure StructureMap by initializing the container with this code below:

public static class ContainerBootstrapper { public static void BootstrapStructureMap() { // Initialize the static ObjectFactory container ObjectFactory.Initialize(x => { x.ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>(); }); } }

Now that that code is called somewhere in the application initialization, we can get an IValidator object from StructureMap like in this sample code by calling ObjectFactory.GetInstance<IValidator>():

public class ClassThatGetsAnIValidator { public void SaveObject(object objectToSave) { // Go get the proper IValidator from StructureMap IValidator validator = ObjectFactory.GetInstance<IValidator>(); var notification = validator.Validate(objectToSave); if (notification.IsValid()) { // save the object } } }

That’s it, your first usage of StructureMap.  No messy Xml configuration, no attributes scattered through your code, just a couple lines of bootstrapping code.   Of course, if that’s all StructureMap did, it wouldn’t be worth your time to download it.  Let’s look at a bit more advanced example.

Primitive Arguments

I actually like to use StructureMap as a generic configuration tool (which was actually its original purpose).  Let’s say you’re moving to the data access code.  You come up with some sort of Repository pattern class like this:

ublic interface IRepository
{
void Save(object target);
}
public class Repository : IRepository
{
public Repository(string connectionString)
{
// set up the persistence infrastructure using the connectionString
// from the constructor argument
}
public void Save(object target)
{
// save the object
}
}

The Repository class needs to be supplied with the “connectionString” in its constructor.  No problem, just set up the value of the constructor argument in the bootstrapping:

ObjectFactory.Initialize(x =>
{
x.ForRequestedType<IRepository>().Use<Repository>()
.WithCtorArg("connectionString").EqualTo("a connection string");
// Or, since it's smelly to embed a connection string directly into code,
// we could pull the connection string from the AppSettings
x.ForRequestedType<IRepository>().Use<Repository>()
.WithCtorArg("connectionString").EqualToAppSetting("CONNECTION-STRING");
});

With the bootstrapping out of the way, when we ask StructureMap for an IRepository in this code:

var repository = ObjectFactory.GetInstance<IRepository>();

StructureMap will look up the “CONNECTION-STRING” value in the AppSettings portion of the App.config file, and use that string value to invoke the constructor function of the Repository class, then hand back that new Repository object.  Woo hoo.  We can build an object that doesn’t depend on anything, and we can build an object that needs some strings in its constructor function.  How about objects that need other non-primitive objects?

Auto Wiring

In the code samples above, I used StructureMap as a Service Locator in the ClassThatGetsAnIValidator.SaveObject() method.  Typically, you’ll try to minimize the number of service locator usages in your system to a bare minimum (I found 8 in my current system, but I think I’ll find a way to prune half of those later).  Most of the value of an IoC tool is in automatically doing Dependency Injection.  I’m working with the new MVC framework at the moment, so it’s a handy sample.  Let’s say that we have a Controller class for a typical CRUD screen.  That Controller class will generally need to interact with both validation services and the data access functionality of the Repository.  Here’s a representative Controller class:

public class SomeScreenController : IController
{
private readonly IRepository _repository;
private readonly IValidator _validator;
// SomeScreenController depends on both IRepository and IValidator
public SomeScreenController(IRepository repository, IValidator validator)
{
_repository = repository;
_validator = validator;
}
}

So let’s get StructureMap set up for this SomeScreenController class:

ObjectFactory.Initialize(x =>
{
// Set up the IValidator
x.ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>();
// Set up the IRepository
x.ForRequestedType<IRepository>().Use<Repository>()
.WithCtorArg("connectionString").EqualToAppSetting("CONNECTION-STRING");
});

You’ll notice that we didn’t make any explicit configuration for the SomeScreenController class, but yet we could now call:

var controller = ObjectFactory.GetInstance<SomeScreenController>();

and StructureMap will happily create a new instance of the SomeScreenController class by invoking its constructor and passing in a new Validator object and a new Repository object created with the connection string from the App.config file.  We didn’t need to tell StructureMap how to construct SomeScreenController because:

  • StructureMap can look at the constructor function of SomeScreenController and see that it depends on IValidator and IRepository
  • StructureMap “knows” about the default way to create and return an IValidator and an IRepository

This feature is known as “auto wiring,” and all the mainstream IoC containers support this feature to some extent or another.

What to do when things go wrong?

StructureMap, and any other IoC tool for that matter, is configuration intensive – which means that their will be problems in that configuration.  We’re all moving to more convention based type registration – which means that more stuff is happening off stage and out of your sight, making debugging the configuration even trickier.  Not to worry (too much), StructureMap has some diagnostic abilities to help you solve configuration problems.  The quickest tool is to ask a Container object or ObjectFactory (which is just a static wrapper around a Container) “what do you have?” with the Container.WhatDoIHave() method like this below:

var container = new Container(x =>
{
x.ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>();
x.ForRequestedType<IRepository>().Use<Repository>()
.WithCtorArg("connectionString").EqualToAppSetting("CONNECTION-STRING");
});
Debug.WriteLine(container.WhatDoIHave());

Which would spit out this text into your output window:

===========================================================================================================
Configuration Sources:
0)   Registry:  StructureMap.ConfigurationExpression,StructureMap
===============================================================================================================================================================================================================================================================================================================================
PluginType                                                                                                                Name                                                                                                 Description                                                                                     
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ShadeTree.Validation.IValidator, ShadeTree, Version=0.8.0.0, Culture=neutral, PublicKeyToken=null                         ShadeTree.Validation.Validator, ShadeTree, Version=0.8.0.0, Culture=neutral, PublicKeyToken=null     ShadeTree.Validation.Validator, ShadeTree, Version=0.8.0.0, Culture=neutral, PublicKeyToken=null
Built by:  StructureMap.Pipeline.BuildPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
StructureMapSample.IRepository, DovetailCRM.IntegrationTesting, Version=0.9.0.0, Culture=neutral, PublicKeyToken=null     27fdf13e-8adc-4f8f-9f53-cf7b35ada80c                                                                 Smart Instance for StructureMapSample.Repository                                                
Built by:  StructureMap.Pipeline.BuildPolicy
===============================================================================================================================================================================================================================================================================================================================

which is admittedly, not the prettiest looking thing in the world.

You can also “assert” that the configuration for a Container or ObjectFactory is complete by calling the Container.AssertConfigurationIsValid() method like this sample below:

var container = new Container(x =>
{
x.ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>();
x.ForRequestedType<IRepository>().Use<Repository>()
.WithCtorArg("connectionString").EqualToAppSetting("CONNECTION-STRING");
});
container.AssertConfigurationIsValid();

 

This method will analyze every thing in the Container configuration and:

  1. Look for any missing constructor or mandatory setter arguments
  2. Look for any unknown dependency types
  3. Look for any errors in the Xml configuration (if you’re using Xml configuration)
  4. Try to build each and every type and named instance in the configuration – i.e. this is a complete, but relatively expensive operation
  5. Run any environment tests configured with the [ValidationMethod] attribute (a feature that is unique to StructureMap as far as I know)

The previous sample is a valid configuration, but let’s look at an invalid configuration.  Let’s omit the configuration of the “connectionString” constructor argument for the Repository class and try AssertConfigurationIsValid():

[Test]
public void lets_see_if_the_container_is_valid()
{
var container = new Container(x =>
{
x.ForRequestedType<IRepository>().Use<Repository>();
//.WithCtorArg("connectionString").EqualToAppSetting("CONNECTION-STRING");
});
container.AssertConfigurationIsValid();
}

 

When I run the unit test above, this is part of the output:

Build Error on Instance '73b7f21b-bbfd-462c-854d-5b2a2f98ba50' (Smart Instance for StructureMapSample.Repository)
for PluginType StructureMapSample.IRepository, DovetailCRM.IntegrationTesting, Version=0.9.0.0, Culture=neutral, PublicKeyToken=null
StructureMap.StructureMapException: StructureMap Exception Code:  205
Missing requested Instance property "connectionString" for InstanceKey "73b7f21b-bbfd-462c-854d-5b2a2f98ba50"

which again, isn’t the prettiest thing in the world, but it does tell me that the “connectionString” argument is missing for the Repository class.  After seeing this output, I think that this output and error wording will get improved in an upcoming release.

Next Prev

 

Leave a Reply

Your email address will not be published. Required fields are marked *