Cutting the Fluff From Service Registration (or How to Do Funky Stuff With CoC, Castle.DynamicProxy & StructureMap)
The more I play around with Convention over Configuration in combination
with StructureMap the more I’m amazed about what you can do with it and
how much it reduces the amount of code you need in order to configure
and wire stuff together. Today I implemented this convention for our
current prototype:
Every class whose class name ends with ‘Service’ and who implements a
service interface ( ‘I’ + ServiceName) is automatically registered as
a Singleton and proxied
The reasoning behind this convention is that I’d like to remove a lot of
the common, redundant instrumentation code from Services in our
application. This includes for instance a lot of the logging, caching or
maybe argument validation aspects. It’s currently implemented using
Castle.DynamicProxy2 although the actual service call interceptors
haven’t been implemented so far. So let’s walk through the code and see
what is necessary in order to realize this.
First of all you need to implement the ITypeScanner interface. Its basic
purpose is to inspect every type which has been picked up in the
scanning process of StructureMap and do container registration with it
in case the type meets the expected criteria. The interface looks like
this.
StructureMap contains a handy base class which contains a lot of helper
methods for implementing a convention, the TypeRules class. The basic
code for my convention looks like this:
My convention
123456789101112131415161718192021222324252627
publicclassServicesAreSingletonsAndProxies:TypeRules,ITypeScanner{#region ITypeScanner Members publicvoidProcess(Typetype,PluginGraphgraph){if(!IsConcrete(type)||!IsService(type)||!Constructor.HasConstructors(type)){return;}varpluginType=FindPluginType(type);if(pluginType==null){return;}varfamily=GetFamiliy(graph,pluginType);varinstance=CreateInstance(pluginType,type);family.AddInstance(instance);family.SetScopeTo(InstanceScope.Singleton);}#endregion }
When my convention inspects a type, it first checks whether the type is
concrete, the type name ends with Service and whether the type has a
public constructor. If any of this criteria is not satisfied the type is
ignored. Then it tries to find the primary interface for the concrete
type. In case an interface has been found a bit StructureMap magic is
applied which configures the DynamicProxy integration and the plugin
family to be scoped as Singletons.
In order to integrate DynamicProxy the registration has to be done a bit
differently compared to how I’ve described it in previous posts. Instead
of using PluginGraph.AddType() I’m using
PluginGraph.AddInstance(IInstance). This gives you some more options for
configuration, including adding InstanceInterceptors which are called
when an instance is resolved via StructureMap. That’s the extension
point I’ve used. The configuration looks like this …
… and the code for the interceptor looks like this …
An Castle.DynamicProxy interceptor
12345678910111213141516171819202122
internalclassDynamicProxyInterceptor:InstanceInterceptor{privatestaticreadonlyProxyGeneratorProxyGenerator=newProxyGenerator();privatereadonlyType_pluginType;publicDynamicProxyInterceptor(TypepluginType){_pluginType=pluginType;}#region InstanceInterceptor Members publicobjectProcess(objecttarget,IContextcontext){returnProxyGenerator.CreateInterfaceProxyWithTargetInterface(_pluginType,target,newLoggingInterceptor());}#endregion }
I’m using proxy creation over interfaces here. I prefer this over the
proxy over classes approach, because it doesn’t force implementation
constraints like having to make every public method virtual or the need
to inherit from MarshalByRef onto the service classes.
That’s basically it. The best of it: The whole rule can be easily tested
in a unit test. The following code uses xUnit.BDDExtensions for this.