skip to the main content area of this page
Patterns and Practices

 

StructureMap Tutorial - Dependency Injection and IoC in .NET


StructureMap is one of a number of dependency injection frameworks for the .NET Framework. StructureMap version 2.5 is expected to be released in the near future. Here are some StructureMap Tutorials to get you started.

 

StructureMap Dependency Injection Basics

In most of your ASP.NET Web Applications, Smart Client Applications, and WPF Applications you are creating reusable services that implement an interface. For example, you might have an interface ILogger that declares the contract for logging in your applications and then have various concrete reusable classes that implement ILogger, such as DatabaseLogger which logs information to a database.

We can tell StructureMap to inject or return DatabaseLogger when there is a request for ILogger with the following statement:

 

StructureMapConfiguration
    .ForRequestedType<ILogger>()
    .TheDefaultIsConcreteType<DatabaseLogger>()
    .CacheBy(InstanceScope.Singleton);

 

In this case we are telling the StructureMapConfiguration to also make the DatabaseLogger a Singleton, which means only 1 instance of DatabaseLogger will be used by the entire application.

You can then use StructureMap's ObjectFactory Class to retrieve an instance of ILogger using the following statement:

 

ILogger logger = ObjectFactory.GetInstance<ILogger>();

 

StructureMap will return an instance of DatabaseLogger based on the fact that we mapped DatabaseLogger to ILogger previously.

We can put this together in a simple Console Application as such

 

namespace StructureMapTutorials
{
    class Program
    {
        static void Main(string[] args)
        {
            StructureMapConfiguration
                .ForRequestedType<ILogger>()
                .TheDefaultIsConcreteType<DatabaseLogger>()
                .CacheBy(InstanceScope.Singleton);

            ILogger logger = ObjectFactory.GetInstance<ILogger>();
        }
    }

    public interface ILogger {}

    public class DatabaseLogger : ILogger {}
}

 

Far more interesting, however, is when StructureMap injects dependencies into objects for us. For example, let's say we also have a  CustomerDataSource Class in our application that requires the ILogger Service.

 

public interface ICustomerDataSource { }

public class CustomerDataSource : ICustomerDataSource
{
    private readonly ILogger _logger;
    public CustomerDataSource(ILogger logger)
    {
        _logger = logger;
    }
}

 

We register the concrete implementation of CustomerDataSource as our service provider for ICustomerDataSource as such just as we did the ILogger Service:

 

StructureMapConfiguration
    .ForRequestedType<ICustomerDataSource>()
    .TheDefaultIsConcreteType<CustomerDataSource>()
    .CacheBy(InstanceScope.Singleton);

 

and then we can ask for an instance of ICustomerDataSource from StructureMap's ObjectFactory Class, which automatically injects the propery ILogger Service into the CustomerDataSource Class' Constructor for us:

 

ICustomerDataSource dataSource =
ObjectFactory.GetInstance<ICustomerDataSource>();

 

You can see how StructureMap does this by running the following Console Application:

 

using StructureMap;
using StructureMap.Attributes;

namespace StructureMapTutorials
{
    class Program
    {
        static void Main(string[] args)
        {
            StructureMapConfiguration
                .ForRequestedType<ILogger>()
                .TheDefaultIsConcreteType<DatabaseLogger>()
                .CacheBy(InstanceScope.Singleton);

            StructureMapConfiguration
                .ForRequestedType<ICustomerDataSource>()
                .TheDefaultIsConcreteType<CustomerDataSource>()
                .CacheBy(InstanceScope.Singleton);

            ICustomerDataSource dataSource =
ObjectFactory.GetInstance<ICustomerDataSource>(); } }
public interface
ILogger { } public class DatabaseLogger : ILogger { } public interface ICustomerDataSource { } public class CustomerDataSource : ICustomerDataSource { private readonly ILogger _logger; public CustomerDataSource(ILogger logger) { _logger = logger; } } }

 

 

StructureMap Registry

Often Dependency Injection and IoC Tools have a way to group related registrations. StructureMap has the concept of a Registry. We could change the code above to group the ILogger and ICustomerDataSource into a ServiceRegistry and register it as such:

 

using StructureMap;
using StructureMap.Attributes;
using StructureMap.Configuration.DSL;

namespace StructureMapTutorials
{
    class Program
    {
        static void Main(string[] args)
        {
            StructureMapConfiguration
                .AddRegistry(new ServiceRegistry());

            ICustomerDataSource dataSource =
ObjectFactory.GetInstance<ICustomerDataSource>(); } }
public class
ServiceRegistry : Registry { protected override void configure() { ForRequestedType<ILogger>() .TheDefaultIsConcreteType<DatabaseLogger>() .CacheBy(InstanceScope.Singleton); ForRequestedType<ICustomerDataSource>() .TheDefaultIsConcreteType<CustomerDataSource>() .CacheBy(InstanceScope.Singleton); } } public interface ILogger { } public class DatabaseLogger : ILogger { } public interface ICustomerDataSource { } public class CustomerDataSource : ICustomerDataSource { private readonly ILogger _logger; public CustomerDataSource(ILogger logger) { _logger = logger; } } }

 

StructureMap PluginFamily and Pluggable Attributes

If you would rather use attributes and have StructureMap scan the various assemblies and automagically register the various types in your application, you can use the PluginFamily and Pluggable Attributes as such:

 

using StructureMap;
using StructureMap.Attributes;
using StructureMap.Configuration.DSL;

namespace StructureMapTutorials
{
    class Program
    {
        static void Main(string[] args)
        {
            StructureMapConfiguration
                .ScanAssemblies()
.IncludeTheCallingAssembly(); ICustomerDataSource dataSource =
ObjectFactory.GetInstance<ICustomerDataSource>(); } } [PluginFamily(
"Database", IsSingleton = true
)] public interface ILogger { } [Pluggable("Database")] public class DatabaseLogger : ILogger { } [PluginFamily("CustomerDataSource", IsSingleton = true)] public interface ICustomerDataSource { } [Pluggable("CustomerDataSource")] public class CustomerDataSource : ICustomerDataSource { private readonly ILogger _logger; public CustomerDataSource(ILogger logger) { _logger = logger; } } }

 

Conclusion

This scratches the surface of using StructureMap for dependency injection and inversion of control in your ASP.NET Web Applications, Smart Client Applications, and WPF Applications.

You can try out other tools as well: Autofac, Castle Windsor, Ninject, SpringFramework.net, and Unity to name a few.

Check out some of the Dependency Injection Screencasts that show Unity, Autofac, and Ninject. Time permitting, I will add a StructureMap Screencast to the mix.

 

Hope this helps,

David Hayden


Tags: DependencyInjection, IoC, StructureMap