Migrating from Simple Injector to StructureMap

StructureMap is the oldest DI container for .NET, and is one of the most commonly used containers. While its configuration can get complex with lots of nested closures, its behavior is much like that the Simple Injector: It allows resolving list types like IEnumerable<T> by default, does not track instances (no need for explicitly releasing instances), and does not suppress configuration errors.

Website http://structuremap.net/structuremap/
Download http://sourceforge.net/projects/structuremap/
Supported platforms .NET 3.5
Code samples based on version 2.6.1

Core differences with Simple Injector

  1. The default lifestyle in StructureMap is Per Request.

Code Samples

The following section contains code snippets that show how to resolve and register instances with the Simple Injector on the left-hand side, and equivalent snippets for StructureMap on the right-hand side.

Resolving Instances

Simple Injector StructureMap
container.GetInstance<IService>(); container.GetInstance<IService>();
container.GetInstane(typeof(IService)); container.GetInstane(typeof(IService));
IEnumerable<IFilter> filters =
    container.GetAllInstances<IFilter>();
IList<IFilter> filters =
    container.GetAllInstances<IFilter>();
IEnumerable<object> filters =
    container.GetAllInstances(typeof(IFilter));
IList filters =
    container.GetAllInstances(typeof(IFilter));

Registration

Registration with a transient lifetime.
Simple Injector StructureMap
// Optional. Concrete instances can be
// resolved without registration
container.Register<RealService>();
// Concrete instances can be resolved without
// registration. However, the default lifetime
// for those instances is Per Request, not
// transient.

container.Configure(r => r.For<RealService>()
.LifecycleIs(new UniquePerRequestLifeStyle()));
container.Register<IService, RealService>(); container.Configure(r => r.For<IService>()
  .LifecycleIs(new UniquePerRequestLifeStyle())
  .Use<RealService>());
container.Register<IService>(() =>
{  
  var log = container.GetInstance<ILogger>();  
  return new RealService(log);
});
container.Configure(r => r.For<IService>()
  .LifecycleIs(new UniquePerRequestLifeStyle())
  .Use(() =>
{
  var log = container.GetInstance<ILogger>();  
  return new RealService(log);
}));
Registration with a singleton lifetime.
Simple Injector StructureMap
container.RegisterSingle<RealService>(); container.Configure(r => r.For<RealService>()
    .Singleton());
container
    .RegisterSingle<IService, RealService>();
container.Configure(r => r.For<IService>()
    .Singleton().Use<RealService>());
container.RegisterSingle<IService>(() =>
{  
    var log = container.GetInstance<ILogger>();  
    return new RealService(log);
});
container.Configure(r => r.For<IService>()
    .Singleton().Use(() =>
{
   var log = container.GetInstance<ILogger>();  
   return new RealService(log);
}));
var instance =
    new RealService(new ConsoleLogger());

container.RegisterSingle<IService>(instance);
var instance =
    new RealService(new ConsoleLogger());

container.Configure(r => r.For<IService>()
    .Use(instance));
container.RegisterAll<IFilter>( 
    new XssInjectionFilter(), 
    new SqlInjectionFilter(), 
    new SmartFilter()
);
container.Configure(r => r.For<IFilter>()
    .Use(new XssInjectionFilter()));
container.Configure(r => r.For<IFilter>()
    .Use(new SqlInjectionFilter()));
container.Configure(r => r.For<IFilter>()
    .Use(new SmartFilter()));
IEnumerable<IFilter> filters = 
    FilterProvider.GetFilters();
container.RegisterAll<IFilter>(filters);

???
container.RegisterInitializer<ICommand>(cmd =>

    cmd.SendAsync = true
    cmd.Logger =
        container.GetInstance<ILogger>();
});
container.Configure(r => r.For<ICommand>()
    .OnCreationForAll(cmd =>
{
    cmd.SendAsync = true
    cmd.Logger =
        container.GetInstance<ILogger>();

}));
// Note: Compared to the SI, SM will also
// call the delegate for manually newed up
// objects. While SI expects users to implement
// custom lifestyles using delegates, in SM
// you should not do this (but implement
// ILifecycle), because SM calls the delegate
// every time an object is returned from a
// delegate, which could lead the delegate
// being called more than once on a single
// instance.

Advanced Scenarios

The SimpleInjector.Extensions.dll contains extension methods for the Container class that enable many advanced scenario’s. The section below how the registrations done with the Extensions library maps to those of StructureMap.

Registration using the non-generic API.
Simple Injector StructureMap
container.Register(typeof(IService),
    typeof(RealService));
container.Configure(r => r
  .For(typeof(IService))
  .LifecycleIs(new UniquePerRequestLifeStyle())
  .
Use(typeof(RealService)));
container.RegisterAll<IFilter>(
    from asm in AppDomain.CurrentDomain
        .GetAssemblies()
    from type in asm.GetExportedTypes()
    where !type.IsAbstract
    where typeof(IFilter).IsAssignableFrom(type)
    select type);
class Transient : IRegistrationConvention
{
  public void Process(Type type, Registry reg)
  {
    var life = new UniquePerRequestLifeStyle();
    reg.For(type).LifecycleIs(life);
  }
}

container.Configure(r =>
{
  foreach (var asm in
      AppDomain.CurrentDomain.GetAssemblies())
  {
    r.Scan(s =>
    {
      s.Assembly(asm);
      s.AddAllTypesOf<IFilter>();
      s.Convention<Transient>();
    });
  }
});
Batch registration of generic interfaces
Simple Injector StructureMap
container.RegisterManyForOpenGeneric(
    typeof(IHandler<>),
    typeof(IHandler<>).Assembly);
class Transient : IRegistrationConvention
{
  public void Process(Type type, Registry reg)
  {
    var life = new UniquePerRequestLifeStyle();
    reg.For(type).LifecycleIs(life);
  }
}

container.Configure(r =>
{
  r.Scan(s =>
  {
    s.Assembly(typeof(IHandler<>).Assembly);
    s.ConnectImplementationsToTypesClosing(
      typeof(IHandler<>));
    s.Convention<Transient>();
  });
});
container.RegisterManyForOpenGeneric(
    typeof(IHandler<>),
    AppDomain.CurrentDomain.GetAssemblies());
class Transient : IRegistrationConvention
{
  public void Process(Type type, Registry reg)
  {
    var life = new UniquePerRequestLifeStyle();
    reg.For(type).LifecycleIs(life);
  }
}

container.Configure(r =>
{
  foreach (var asm in
      AppDomain.CurrentDomain.GetAssemblies())
  {
    r.Scan(s =>
    {
      s.Assembly(typeof(IHandler<>).Assembly);
      s.ConnectImplementationsToTypesClosing(
        typeof(IHandler<>));
      s.Convention<Transient>();
    });
  }
});
var asm = typeof(IHandler<>).Assembly;

container.RegisterManyForOpenGeneric(
    typeof(IHandler<>),
    from type in asm.GetTypes()
    where !type.IsAbstract
    where type.Name.EndsWith("Handler")
    select type);
class Transient : IRegistrationConvention
{
  public void Process(Type type, Registry reg)
  {
    var life = new UniquePerRequestLifeStyle();
    reg.For(type).LifecycleIs(life);
  }
}

container.Configure(r =>
{
  r.Scan(s =>
  {
    s.Assembly(typeof(IHandler<>).Assembly);
    s.Exclude(t => !t.Name.EndsWith("Handler"));
    s.ConnectImplementationsToTypesClosing(
      typeof(IHandler<>));
    s.Convention<Transient>();
  });
});
Mapping of open generic types to an open generic implementation
Simple Injector StructureMap
container.RegisterOpenGeneric(
    typeof(IValidator<>),
    typeof(NullValidator<>));
container.Configure(r => r
  .For(typeof(IValidator<>))
  .LifecycleIs(new UniquePerRequestLifeStyle())
  .Use(typeof(NullValidator<>)));

 

typeof(IFilter).IsAssignableFrom(type)

Last edited Oct 6, 2012 at 12:51 PM by dot_NET_Junkie, version 8