Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

Wicked Cool Jobs

Syndication

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Create your own Auto Registration Convention with StructureMap

In StructureMap 2.5 I added the ability to make "auto registration" policies that would enable StructureMap to just scan an assembly and figure out how to register types on its own. This is yet one more example of the new trend in .Net circles for adopting "Convention over Configuration" to make our work go faster.  There'll be a backlash against that sometime soon, but for now, I think it's a significant trend to watch play out in the .Net OSS space.

This blog post is excerpted from the online documentation as http://structuremap.sourceforge.net/ScanningAssemblies.htm.  The one and only Laribee asked me to write some samples of auto registration.  My respect and affection for Dave is so strong that it only took me 6 weeks to get around to it.

 

StructureMap 2.5+ adds the ability to do convention based type registration.  Convention over Configuration is becoming increasingly more common as a way to reduce the overhead of using configuration intensive tools.  Type registration conventions can be mixed and matched with explicit configuration.

The Default Convention

When using StructureMap over the last couple years I saw a lot of type registrations like:

            Start<ICommandExecutor>().TheDefaultIsConcreteType<CommandExecutor>();

There was a reoccuring pattern.  "Foo" was the default implementation of "IFoo."  The "I" moniker is the last vestige of Hungarian Notation left in my coding style, but it refuses to go away, so let's just take advantage of that naming convention with a new DefaultConvention. 

Let's say that we have a class and interface like:

    public interface IConvention

    {

    }

 

    public class Convention : IConvention

    {

    }

To make Convention be the default type for IConvention, I can simply scan the assembly containing these types with the new default convention:

            var container = new Container(registry =>

            {

                registry.Scan(x =>

                {

                    x.TheCallingAssembly();

                    x.With<DefaultConventionScanner>();

                });

            });

 

            container.GetInstance<IConvention>().ShouldBeOfType<Convention>();


Registering Types by Name

One of the simplest, but yet most useful, ways to use convention based auto registration is just to add all concrete types that can be cast to a certain PluginType and use a convention to determine the Instance name.  The first place I used this functionality was at the beginning of our MVC project.  Let's say that we name our Controller classes like this:

    public interface IController{}

    public class AddressController : IController{}

    public class SiteController : IController{}

As a convention, we'd like to register AddressController as the "Address" of IController, and "Site" or IController like this:

            container = new Container(x =>

            {

                x.ForRequestedType<IController>().AddInstances(o =>

                {

                    o.OfConcreteType<AddressController>().WithName("Address");

                    o.OfConcreteType<SiteController>().WithName("Site");

                })

            });

Over 50+ Controller classes, that coding is going to get extremely tedious.  Let's use a convention instead:

            container = new Container(x =>

            {

                x.Scan(o =>

                {

                    o.TheCallingAssembly();

                    o.AddAllTypesOf<IController>().NameBy(type => type.Name.Replace("Controller", ""));

                });

            });

 

            foreach (var instance in container.Model.InstancesOf<IController>())

            {

                Debug.WriteLine(instance.Name + " is " + instance.ConcreteType.Name);

            }

When this code is executed, we get this output:

Address is AddressController
Site is SiteController

Here's the unit test code for this functionality:

        [Test]

        public void can_find_objects_later_by_name()

        {

            container.GetInstance<IController>("Address")

                .ShouldBeOfType<AddressController>();

 

            container.GetInstance<IController>("Site")

                .ShouldBeOfType<SiteController>();

        }


Creating and Using Your Own Convention

To write your own auto registration convention, write a concrete class that implements the ITypeScanner interface:

    public interface ITypeScanner

    {

        void Process(Type type, PluginGraph graph);

    }

Inside a custom ITypeScanner, you add types to a Container by modifying the PluginGraph object that is passed into the TypeScanner.  While having access to the PluginGraph allows you to make any possible type of configuration change (PluginGraph is the Semantic Model behind both the Registry DSL and the Xml configuration), in practice you probably only care about these three methods:

        /// <summary>

        /// Adds the concreteType as an Instance of the pluginType

        /// </summary>

        /// <param name="pluginType"></param>

        /// <param name="concreteType"></param>

        void AddType(Type pluginType, Type concreteType);

 

        /// <summary>

        /// Adds the concreteType as an Instance of the pluginType with a name

        /// </summary>

        /// <param name="pluginType"></param>

        /// <param name="concreteType"></param>

        /// <param name="name"></param>

        void AddType(Type pluginType, Type concreteType, string name);

 

        /// <summary>

        /// Add the pluggedType as an instance to any configured pluginType where pluggedType

        /// could be assigned to the pluginType

        /// </summary>

        /// <param name="pluggedType"></param>

        void AddType(Type pluggedType);

Here's a sample type convention from my current project:

    /// <summary>/span>

    /// This TypeScanner looks for any concrete class that implements

    /// an IFlattenerFor<T> interface, and registers that type

    /// against the closed IFlattenerFor<T> interface,

    /// i.e. IFlattenerFor<Address> or IFlattenerFor<Site>

    /// </summary>

    public class DtoFlattenerConventionScanner : ITypeScanner

    {

        public void Process(Type type, PluginGraph graph)

        {

            Type interfaceType = type.FindInterfaceThatCloses(typeof (IFlattenerFor<>));

            if (interfaceType != null)

            {

                graph.AddType(interfaceType, type);

            }

        }

&    }

You apply the custom ITypeScanner by simply calling With() inside of a Scan() block:

            Scan(x =>

            {

                // scan with a custom ITypeScanner

                x.With<DomainEntityAliaser>();

                x.With<QueueItemMappingScanner>();

            });


Posted Tue, Jan 20 2009 7:06 AM by Jeremy D. Miller
Filed under:

[Advertisement]

Comments

Daniel Fernandes wrote re: Create your own Auto Registration Convention with StructureMap
on Tue, Jan 20 2009 7:54 AM

Good to see StructureMap moving along so quickly.

I will definitely give it a go next time I start a project, I'm finding it frustrating there hasn't been a realease of CastleWindsor in a long while.

Harry M wrote re: Create your own Auto Registration Convention with StructureMap
on Tue, Jan 20 2009 11:42 AM

I love this stuff, the concept of auto registering stuff etc etc is awesome, but I am finding all the auto-registration APIs a bit annoying. I need one for Fluent NHib, one for my IoC container, one for the one I use at home etc. etc.

If you have a simple Register(Type interface, Type implementer) and LINQ you can just write something like

   foreach (var interfaceType in typeof(IService).Assembly.GetTypes().Where(MyConvention)

           {

               foreach (var implementerType in classes.GetTypes().Where(t => interfaceType.IsAssignableFrom(t)))

               {

                   Register(interfaceType, interfaceType.FullName);

               }

           }

OK so its not as terse, but everyone on the team can tell at a glance what it's doing and you can customise it to your hearts content.

Harry M wrote re: Create your own Auto Registration Convention with StructureMap
on Tue, Jan 20 2009 11:44 AM

whoops I meant

Register(interfaceType, implementerType);

Create your own Auto Registration Convention with StructureMap … wrote Create your own Auto Registration Convention with StructureMap &#8230;
on Tue, Jan 20 2009 7:58 PM

Pingback from  Create your own Auto Registration Convention with StructureMap &#8230;

DotNetShoutout wrote Create your own Auto Registration Convention with StructureMap - Jeremy D. Miller -- The Shade Tree Developer
on Wed, Jan 21 2009 11:37 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Jon Kruger wrote re: Create your own Auto Registration Convention with StructureMap
on Thu, Jan 22 2009 7:59 PM

I've been doing this kind of thing inside my Registry classes (in the configure() method)... I'll use reflection to figure out how to auto-wire things using ForRequestedType<ISomething>().TheDefaultIsConcreteType<Something>().

Is this way you've documented somehow better than what I'm doing or is it just another way to do it?

Jon

Jeremy D. Miller wrote re: Create your own Auto Registration Convention with StructureMap
on Thu, Jan 22 2009 8:01 PM

@Jon,

As long as you're happy with what you got, I say leave it alone.

Matthew Podwysocki wrote Functional Programming in .NET – Adding Extensibility
on Sat, Mar 14 2009 2:03 AM

Thanks for everyone who attended my session on applied functional programming earlier this week at RockNUG

Matthew Podwysocki's Blog wrote Functional Programming in .NET – Adding Extensibility
on Sat, Mar 14 2009 2:07 AM

Thanks for everyone who attended my session on applied functional programming earlier this week at RockNUG

Community Blogs wrote Functional Programming in .NET – Adding Extensibility
on Mon, Mar 16 2009 12:02 PM

Thanks for everyone who attended my session on applied functional programming earlier this week at RockNUG

Add a Comment

(required)  
(optional)
(required)  
Remember Me?
Devlicio.us