views:

263

answers:

2

I am learning about best practices in MVC2 and I am knocking off a copy of the "Who Can Help Me" project (http://whocanhelpme.codeplex.com/) off Codeplex. In it, they use Castle Windsor for their DI container. One "learning" task I am trying to do is convert this subsystem in this project to use StructureMap.

Basically, at Application_Start(), the code news up a Windsor container. Then, it goes through multiple assemblies, using MEF, in ComponentRegistrar.cs:

public static class ComponentRegistrar
{
  public static void Register(IContainer container)
    {
        var catalog = new CatalogBuilder()
                          .ForAssembly(typeof(IComponentRegistrarMarker).Assembly)
                          .ForMvcAssembly(Assembly.GetExecutingAssembly())
                          .ForMvcAssembliesInDirectory(HttpRuntime.BinDirectory, "CPOP*.dll") // Won't work in Partial trust
                          .Build();

        var compositionContainer = new CompositionContainer(catalog);

        compositionContainer
            .GetExports<IComponentRegistrar>()
            .Each(e => e.Value.Register(container));
    }
}

and any class in any assembly that has an IComponentRegistrar interface will get its Register() method run.

For example, the controller registrar's Register() method implementation basically is:

public void Register(IContainer container)
{
    Assembly.GetAssembly(typeof(ControllersRegistrarMarker)).GetExportedTypes()
            .Where(IsController)
            .Each(type => container.AddComponentLifeStyle( 
                             type.Name.ToLower(), 
                             type, 
                             LifestyleType.Transient ));
}

private static bool IsController(Type type)
{
    return typeof(IController).IsAssignableFrom(type);
}

Hopefully, I am not butchering WCHM too much. I am wondering how does one do this with StructureMap? I'm assuming that I use Configure() since Initialize() resets the container on each call? Or, is tit a completely different approach? Do I need the MEF-based assembly scan, used to find all registrars and run each Register(), or is there something similar in StructureMap's Scan()?

+1  A: 

Have a look at StructureMap's registries (http://structuremap.github.com/structuremap/RegistryDSL.htm). To control the lifecycle use something like:

For<ISomething>().Use<Something>().LifecycleIs(new SingletonLifecycle());

(Transient is the default).

When you bootstrap the container you can say:

ObjectFactory.Initialize(c => c.Scan(s => {
    s.WithDefaultConventions();
    s.LookForRegistries();
}
grahamrhay
As I understand it, I can only call Initialize() once. So, ObjectFactory.Initialize() has to be made the equivalent of ComponentRegistrar.Register()? Scan() would replace the MEF code? Instead of implementations of IComponentRegistrar's Register(), I just create multiple Registry classes? And, lastly, will Scan() scan across multiple assemblies? The MEF code will scan across multiple projects/assemblies.
alphadogg
I decided to keep MEF in order to allow for the possibility that I may want Register() to do more than just get items into the StructureMap container. This required the code in my answer in this question.
alphadogg
+1  A: 

Feel dirty, answering my own question, but I did the following:

public class ControllerRegistrar : IComponentRegistrar
    {
        public void Register(IContainer container)
        {
            container.Configure(x =>
            {
                x.Scan(scanner =>
                {
                    scanner.Assembly(Assembly.GetExecutingAssembly());
                    scanner.AddAllTypesOf<IController>().NameBy(type => type.Name.Replace("Controller", ""));
                });
            });

        }
    }

I am not 100% sure this is right, but it works. Pulled it primarily from the "Registering Types by Name" section of this StructureMap doc page.

alphadogg