7

I am using mvc.net with StructureMap to scan and register all repositories and services for me. Now I want to register and cache by Singleton. How can I do?

 IContainer container = new Container(x => {
            // Register Repositories and Services
            x.Scan(y => {
                y.AssemblyContainingType<SomeRepository>();
                y.AssemblyContainingType<SomeService>();

                y.IncludeNamespaceContainingType<SomeRepository>();
                y.IncludeNamespaceContainingType<SomeService>();
            });   

            // Register Controllers
            x.Scan(y => {
                y.TheCallingAssembly();
                y.AddAllTypesOf<IController>().NameBy(type => type.Name.Replace("Controller", ""));
            });
        });
Jørgen R
  • 10,568
  • 7
  • 42
  • 59
ensecoz
  • 900
  • 10
  • 16

3 Answers3

19

Using the new API in 2.6, ITypeScanner is deprecated. This should be implemented as a convention instead. A simple example is you want to register a convention that all types of a particular interface are a singleton:

    Scan(a =>
    {
        a.AssemblyContainingType<IMyPluginType>();
        a.With(new SingletonConvention<IMyPluginType>());
        a.AddAllTypesOf<IMyPluginType>();
    });

Then:

    internal class SingletonConvention<TPluginFamily> : IRegistrationConvention
    {
        public void Process(Type type, Registry registry)
        {
            if (!type.IsConcrete() || !type.CanBeCreated() || !type.AllInterfaces().Contains(typeof(TPluginFamily))) return;

            registry.For(typeof(TPluginFamily)).Singleton().Use(type);
        }
    }
Eric Hauser
  • 5,551
  • 3
  • 26
  • 29
  • +1 BTW, no need to call a.AddAllTypesOf(); in Scan() as the SingletonConvention.Process() will reg the type(s). – ozczecho Mar 31 '11 at 05:31
  • Why do I need those 3 lines in `Scan`? What's the difference between `a.With(new SingletonConvention());` and `a.AddAllTypesOf();`? Are those two really necessary? And if I have other interface, do I need to use both lines again? – tyron Jan 11 '12 at 14:23
  • Overly verbose, but worked like a champ. Really think that if statement should need used, but i'm not going to change the API. After saying that i won't change the api, it still doesn't mean i can't just do better – Chris Marisic Mar 10 '14 at 17:53
2

You'll need to implement the ITypeScanner similar to what Jeremy Miller outlines at http://codebetter.com/blogs/jeremy.miller/archive/2009/01/20/create-your-own-auto-registration-convention-with-structuremap.aspx

So for your Controllers for instance, I would change that Scan call to be:

x.Scan(y => {
    y.TheCallingAssembly();
    y.With<MyNewTypeScanner>();
});

Then I would define a class elsewhere that looked something like this:

public class MyNewTypeScanner: ITypeScanner
{
    //This method is responsible for determining if a type should be registered
    // and then passing it to RegisterType() if so
    public void Process(Type type, PluginGraph graph)
    {
        //At this point you would probably just test to see if type is IController
        //but you can get more sophisticated without too much headache.

        this.RegisterType(graph, type);
    }


    private void RegisterType(PluginGraph graph, Type implementingType)
    {
        //The argument passed to FindFamily must be the type/class that will be requested out of SM
        var family = graph.FindFamily(implementingType);

        family.AddType(implementingType);
        family.SetScopeTo(InstanceScope.Singleton);
    }
}

This should do the trick for you.

sparker
  • 356
  • 3
  • 7
0

Expanding upon the answer from @Eric Hauser creating a more readily usable solution

public abstract class TypedRegistrationConvention<TPluginFamily> 
                                        : IRegistrationConvention
{
    public virtual void Process(Type type, Registry registry)
    {
        if (!type.IsConcrete() 
            || !type.CanBeCreated() 
            || !type.AllInterfaces().Contains(typeof (TPluginFamily))) 
            return;

        ApplyConvention(type, registry);
    }

    public abstract void ApplyConvention(Type type, Registry registry);
}

With this established base class once, you can then implement conventions without having to muck around with the type checking code.

public class SingletonConvention<TPluginFamily> 
                                : TypedRegistrationConvention<TPluginFamily>
{
    public override void ApplyConvention(Type type, Registry registry)
    {
        registry.For(typeof (TPluginFamily)).Singleton().Use(type);
    }
}

Much simpler class in the end.

Chris Marisic
  • 32,487
  • 24
  • 164
  • 258