CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

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?



Comments

Emanuele DelBono said:

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.

# January 28, 2008 3:30 AM

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# January 28, 2008 3:31 AM

Pages tagged "proxy" said:

Pingback from  Pages tagged "proxy"

# January 28, 2008 7:00 AM

Björn Rochel said:

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 :-)).

# January 28, 2008 7:32 AM

Rob said:

Very intuitive.

# January 28, 2008 9:01 AM

Jason said:

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<ISecurityService>();

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.)

# July 17, 2008 12:00 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

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 previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

Our Sponsors

Free Tech Publications

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP