Interception techniques in StructureMap 2.5

The 2.5 release of StructureMap is at least 6 weeks away, but I’d like to throw some more stuff out to get some feedback while I’ve got plenty of time to deviate.  I’m building in much more interception capabilities into StructureMap to support runtime AOP and other scenarios.  I don’t have a good background in AOP, so I’m guessing as much as anything about what I need.  Here’s a rundown of what I’ve got so far.  The code is targeted to .Net 2.0.  My plan is to release for 2.0, then immediately turn around and do a .Net 3.5 release.  So please mentally substitute in lambda expressions for the anonymous delegates.  All of this code is in the StructureMap trunk, and I’m running my development project off of the current revision.

 

Intercept a particular instance being created

When a particular instance is created you want to do something with that instance before it’s returned from StructureMap.  The configuration code is below:

 

            registry.ForRequestedType<IService>()
                .AddInstance(
                Instance<IService>().UsingConcreteType<ColorService>()
                    .OnCreation<ColorService>(delegate(ColorService s) { _lastService = s; })
                );

You just pass a delegate or lambda expression to the OnCreation() method like this:

    public delegate void StartupHandler<T>(T target);

I envision this being used mostly to run extra bootstrapping or register objects with event brokers.  Now, if you want to enrich the object with some sort of runtime AOP or wrap it with a decorator, you would do this:

 

            registry.ForRequestedType<IService>()
                .AddInstance(
                Instance<IService>().UsingConcreteType<ColorService>()
                    .EnrichWith<IService>(delegate(IService s) { return new DecoratorService(s); })
                )

 

Again, you just pass in a delegate or lambda into the EnrichWith() method, but this time you’re required to return an object.  The delegate signature is this:

    public delegate T EnrichmentHandler<T>(T target);

It might be tedious to define these handlers per instance, so let’s move on to broader categories.

 

Intercept every instance of a requested type

It’s basically the same mechanics, except that you register the EnrichmentHandler or StartupHandler on the ForRequestedType<T> (BuildInstancesOf<T>) expression like these examples:

            _registry.ForRequestedType<IService>()
                .OnCreation(delegate(IService s) { _lastService = s; })
                .AddInstance(
                ConstructedBy<IService>(delegate { return new ColorService("Green"); })
                    .WithName("Green"))
                ;
 
 
            _registry.ForRequestedType<IService>()
                .EnrichWith(delegate(IService s) { return new DecoratorService(s); })
                .AddInstance(
                ConstructedBy<IService>(delegate { return new ColorService("Green"); })
                    .WithName("Green"))
                ;

 

The first snippet directs StructureMap to execute a delegate against every new instance of IService created.  The second snippet would give you the ability to replace any new instance of type IService created with an enriched type or decorator.

All of these examples so far have worked on an object created by StructureMap shortly after it was created.  Now, what if you want to intercept the request itself and return something entirely different depending on circumstances?  For a couple years, StructureMap has an extensibility mechanism called an InstanceFactoryInterceptor that acts much as an IHttpModule in ASP.Net to decorate the normal InstanceFactory object that builds a given family of instances.  I’ve used that mechanism to create the “scoping” feature that allows you to make instances either singleton’s or thread local or HttpContext specific.  As I said, it’s been a feature for awhile, but never documented and got cut from the original release of the fluent interface.  I’m fixing that with the 2.5 release like so:

            AnInstanceFactoryInterceptor factoryInterceptor = new AnInstanceFactoryInterceptor();
 
            PluginGraph pluginGraph = new PluginGraph();
            using (Registry registry = new Registry(pluginGraph))
            {
                registry.BuildInstancesOf<IGateway>().InterceptConstructionWith(factoryInterceptor);
            }
 

I suppose you could use this to register an AOP handler, but I see this primarily as a way to do instance caching or switch out the actual instances returned by some sort of security rules.  You might use this to return a read only implementation of IView for some roles, and an editable implementation of IView for other roles.

Intercept any instance of any type that meets this criteria

Okay, now we come to the feature that’s very specifically intended for AOP.  What if you want your runtime AOP engine to intercept any type that’s decorated with the magic AOP attributes?  You could implement a new class that implements the TypeInterceptor interface shown below:

    public interface InstanceInterceptor
    {
        object Process(object target);
    }
 
    public interface TypeInterceptor : InstanceInterceptor
    {
        bool MatchesType(Type type);
    }

You just need to implement two methods.  MatchesType(Type) can look at a .Net Type and determine if the TypeInterceptor can act upon an instance.  The Process() method acts as the EnrichmentHandler delegate to return any kind of decorator or runtime AOP proxy instead of the original instance.  You would register TypeInterceptor like this:

 

            MockTypeInterceptor interceptor = new MockTypeInterceptor();
            registry.RegisterInterceptor(interceptor);
 
            // or
 
            StructureMapConfiguration.RegisterInterceptor(interceptor);

You can register more than one TypeInterceptor.  The result of MatchesType() is cached by Type, so subsequent creations of a concrete class will not have to call expensive reflective calls to match the types.

 

 

Well, waddaya think?  Useful, or do you need something else entirely?

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Featured, StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • SMHoff

    This is no longer available in StructureMap as of Feb. 2009. The method call of ForRequestedService().AddInstance does not exist.

  • http://www.superbia.no BjartN

    I did an implementation using StructureMap and Spring.NET AOP.. Works like a charm (http://www.superbia.no/post/2009/01/09/Using-StructureMap-and-SpringNET-to-add-security-to-my-repository.aspx)

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Vladimir,

    Yes, but can you post the question to:
    http://groups.google.com/group/structuremap-users?hl=en

    Thanks,

    jeremy

  • http://pro-thoughts.blogspot.com/2008/11/best-of-f-and-c-nemerle-scala-various.html Vladimir Kelman

    @Jeremy,
    Is it possible to Intercept every instance of a type which implements a particular interface?

  • Jason

    I like what you’ve done here, but I think I’m looking for a combo of what you have outlined. I’d like a way to globally intercept the requested type, and then build an instance dynamically on for that type, but I don’t want to register the specific types. For example:

    ISecurityService securityService = ObjectFactory.GetInstance();

    And then in the background, and an interceptor build the instance for that requested type (e.g. see if the requested type has the ServiceContract attribute, and make the WCF calls to get the proxy, etc.)

  • http://www.bluespire.com/blogs Rob

    Very intuitive.

  • Björn Rochel

    Looks very promising to me. A nice addition to the already well maintainable configuration style of StructureMap. I also like the fact that the implementation is based on ‘good old’ design techniques like the decorator pattern instead of using some sort of ‘post compiler weaving’ for the AOP support. That makes it more predictable and easier testable ( at least for me :-)).

  • http://blogema.wordpress.com Emanuele DelBono

    I like it: it’s very simple to setup and easy to use.
    What about filtering? I mean, wouldn’t be great if I can decide to intercept only some methods/properties on a type.