StructureMap: Medium-level Usage Scenarios


This is a follow-on to my previous post about basic usage scenarios for StructureMap.  This post will focus on slightly more advanced usage scenarios and how StructureMap handles them.  For those playing the home game, I’m still working on the ‘Exploring ShadeTree’ series, but it’s hit a small roadblock because there are some design changes pending on the NHibernate stuff I was going to cover. Please bear with me.  Anyhow, in the meantime, I hope you find these StructureMap guides helpful.

Auto-wiring Factory

I have many objects I wish to manage who have dependencies upon each other. Managing the construction and assembly of these objects is complicated and tedious. When I request an IFoo, I want to get back an instance of Foo with all its dependencies satisfied.

Let’s assume you have the IFoo/Foo combination, in addition to IBar/Bar, and IBaz/Baz.   Let’s also say that Foo has a dependency on both IBar and IBaz.  The current recommended way of handling this situation is to define a constructor for Foo() that receives an instance of IBar and IBaz.

Consider this type structure:

public interface IBar{}
public class Bar : IBar{}

public interface IBaz{}
public class Baz : IBaz{}

public interface IFoo{}

public class Foo : IFoo
{
    public Foo( IBar bar, IBaz baz )
    {
    }
}

The StructureMap configuration for this structure would look like this:

StructureMapConfiguration
    .ForRequestedType<IBar>().TheDefaultIsConcreteType<Bar>();

StructureMapConfiguration
    .ForRequestedType<IBaz>().TheDefaultIsConcreteType<Baz>();

StructureMapConfiguration
    .ForRequestedType<IFoo>().TheDefaultIsConcreteType<Foo>();

 

And then, to get a Foo instance with all its dependencies satisfied, simply use ObjectFactory.GetInstance like normal:

IFoo fooInstance = ObjectFactory.GetInstance<IFoo>();

 

Note that no where did you have to explain to StructureMap that Foo was dependent upon Bar or Baz. StructureMap figured it out automatically!  This concept is known as “autowiring”.  By default, StructureMap will attempt to satisfy as many dependencies as it can.  It will attempt to use the ‘greediest’ constructor (the one with the most parameters).  If your class has two constructors, one has just IBar and the other has IBar and IBaz, StructureMap will try to use the IBar and IBaz constructor.

Isolated Configuration (Registration of Dependencies)

I have many objects in many assemblies (some of which may not be known at compile time). Or, I don’t like having every single object in my StructureMap configuration defined in my startup routine. Is there a way that each unit of deployment can specify it’s own object dependency registration?

So in our project at work, we have a few assemblies that have varying concerns such as Web (our ASP.NET MVC project) and Core (pretty much everything else).  Within Core, we have several areas of concern such as Domain model, Persistence, Web (everything related to Web applications in general – stuff we can reuse on other web projects).  Each of these areas of concern has a class that derives from Registry. No, this has nothing to do with the Windows Registry, this is in the context of ‘object dependency registration.’  You can create a class which derives from StructureMap.Configuration.DSL.Registry and override the configure() method.  In this method, you should register the objects that are “local” to the Registry class. For example, your ‘WebRegistry’ class would register all the controllers, any HttpContext abstractions, and things like that.

Another, perhaps better, example case for this might be a composite UI/SmartClient type application (think CAB, Prism, etc) where entire portions of the application are loaded at runtime from external assemblies. It’s actually impossible for the central application startup code to know all the components that will be loaded into the system. In this case, Registries really shine.</p> </p> </p> </p> </p> </p> </p> </p> </p> </p>

Consider this contrived example of what a PersistenceRegistry class might look like:

public class PersistenceRegistry : Registry
{
    protected override void configure()
    {
        ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>();
        ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>();
        ForRequestedType<ISecurityDataService>().TheDefaultIsConcreteType<SecurityDataService>();
    }
}

Notice how it has only the stuff related to persistence and nothing about controllers or anything like that? 

In order for these Registries to take effect, you must let StructureMap know of their existence. One way is to tell it implicitly using the AddRegistry method, like so:

StructureMapConfiguration.AddRegistry(new PersistenceRegistry());

</p> </p>

Auto-discovery of Configuration

I have several registries including ones that I don’t know about at compile time. It would be nice if these could be auto-discovered.

Another way in which to invoke StructureMap Registries, which also happens to be the the preferred method of doing so, is to tell StructureMap to scan through the assemblies you tell it to scan through (including the current one, if you tell it to do so). StructureMap will automatically recognize types deriving from Registry and invoke their configure() method.  There are two primary use cases for this behavior: 1.) You know all the assemblies at compile time and 2.) You do not know all the assemblies at compile time.  For the first case, consider the following example:

StructureMapConfiguration
    .ScanAssemblies()
    .IncludeTheCallingAssembly()
    .IncludeAssemblyContainingType<CoreRegistry>()
    .IncludeAssemblyContainingType<PersistenceRegistry>()
    .IncludeAssemblyContainingType<WebSharedRegistry>()
    .IncludeAssemblyContainingType<OurWebApplicationRegistry>();

As you can see here, we’re explicitly telling StructureMap to load the current assembly, plus our contrived “Core”, “Persistence”, “WebShared”, and “OurWebApplication” assemblies which each have their own Registry implementations.  Note that if it just so happened that TheCallingAssembly was also OurWebApplicationRegistry’s assembly, StructureMap would handle that gracefully and would not result in duplicate registrations.

As for the other case — the dynamically-loading-assemblies case – you’ll just need to call ScanAssemblies().IncludeTheCallingAssembly() from the initialization/startup/bootstrap method of your plugin.  For example, assuming you’re using some sort of SmartClient/Composite UI application, when you load in a new module, you’re likely going to have some sort of entry point into the module (i.e. a well known IModule interface that some class implements that has an Initialize() method on it of some sort).  Put your ScanAssemblies().IncludeTheCallingAssembly() call in there or have it called by your Initialize() method.  Your module/plug-in’s Registry implementation will know all about the dependencies of your module and when you inform StructureMap of this, the module and all its dependencies will be loaded into the container and your module will be ready to go.</p>

Profiles, Alternate Configurations

Certain objects I’ve defined in my container are not appropriate in all circumstances. I would like to have one concrete instance returned when my application is running in Mode A and a different instance returned when my application is running Mode B.</p>

A common scenario we use at work is “Live” and “Stubbed” where live usually means “connected to the database and external services” and “stubbed” means “it’s not connected to anything outside the application.”  This is, of course, useful for integration testing and for quick smoke tests, etc where full connectivity might not be required. Another example might be the “Google Map API” or “Yahoo Map API” profiles where some different services with different underlying implementations may be warranted, etc.

First, declare your dependencies like normal. Then, create a new profile and declare the differences. New profiles will gain all the configuration of the default/unnamed profile, so you only need to define what is different.  Remember our PersistenceRegistry up above?  He’s an example of how it might change when the concept of profiles are introduced:

public class PersistenceRegistry : Registry
{
    protected override void configure()
    {
        ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>();
        ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>();
        ForRequestedType<ISecurityDataService>().TheDefaultIsConcreteType<SecurityDataService>();

        CreateProfile("Stubbed")
            .For<IRepository>().UseConcreteType<InMemoryRepository>()
            .For<ISecurityDataService>().UseConcreteType<StubSecurityDataService>();
    }
}

</p> </p> </p> </p> </p> </p> </p> </p> </p> </p> </p> </p> </p> </p> </p> </p> </p> </p>

Note the ‘CreateProfile’ call.  When StructureMap’s current profile changes to “Stubbed”, requests for IRepository will receive an InMemoryRepository instead of a normal Repository object.

In order to use this profile, you can do a number of things (this list is not comprehensive, I’m sure I’m missing something else): 1.) Call TheDefaultProfileIs(“YourProfileName”), 2.) Drop a StructureMap.Config file in your bin folder or web root.

#1 is easy, somewhere in your startup code, when you’ve determined (somehow) that you need to load a specific profile, you can simply call StructureMapConfiguration.TheDefaultProfileIs(“SomeOtherProfile”).

#2 is also pretty easy. When we want to run in ‘stubbed’ mode, we simply drop a mostly-empty StructureMap.config file into our web root (see example below). When we want to run ‘live’ again, we remove the file. Pretty easy, huh?  Here’s what our stubbed file looks like:

<StructureMap MementoStyle="Attribute" DefaultProfile="Stubbed">
</StructureMap>

Conclusion

That’s a good chunk of stuff for right now, there may be a few other medium scenarios that aren’t coming to mind right now. Please feel free to suggest some and I’ll look into it.

In the next post, I’m going to go into some more advanced scenarios such as convention scanners, more manual/fine-grained object construction, construction-via-lambda, direct object container injection, and possibly a few others.

StructureMap: Basic Scenario Usage