Adding a Policy Injection extension to Unity
One of the things that excited me when I first heard about Unity was the possibility to combine both Dependency Injection and Policy Injection. So when I downloaded the CTP I was a bit dissapointed that it was not (yet?) supported out of the box. The good thing about Unity though is that is supports extensions. These extensions dive directly under the hood to the underlying ObjectBuilder2 framework. Extensions are build up with Strategies and Policies just like you would with ObjectBuilder2.
The basic idea I had was to use the wrapping mechanism of the Policy Injection block to wrap the objects created by Unity in one of the last building stages. This way I do not have to care about constructor arguments.
The first thing I tried to do was to create a PolicyInjectionStrategy. ObjectBuilder creates and decorates it's objects using a series of strategies. I let the PolicyInjectionStrategy derive from BuilderStrategy and did an override of the BuildUp method. The BuildUp method has a couple of arguments:
context: provides information about the total build up process and contains the policies
buildKey: provides information about the type being created
existing: the object that has been created in earlier stages of the strategy chain.
To use the wrapping mechanism of the Policy Injection block you need either one of the following:
- A type that derives from MarshalByRefObject
- A type that exposes an explicit interface
This gave me a bit of a problem. Because I try to do this in one of the last build up stages the buildKey argument only provides me information about the type being created and not of the interface that may have been used to instantiate the object. In te very beginning this information is available but quickly overwritten by the BuildKeyMappingStrategy. I explored all of the arguments of the BuildUp method and the only thing I could possibly use was the browse through the policies and try to reverse the process of the BuildKeyMappingStrategy. An ugly and not very stable solution.
So I decided to dive a little deeper and alter both Unity and ObjectBuilder2 a bit. The first thing I did was to alter the interface of the type of the buildKey argument (ITypeBasedBuildKey) by adding a TypeFrom propery:
32 Type TypeFrom
33 {
34 get;
35 }
and the class that implements it: NamedTypeBuildKey. I also added a constructor to accept a value for typeFrom.
36 public NamedTypeBuildKey(Type type, string name, Type typeFrom)
37 {
38 this.type = type;
39 this.name = name;
40 this.typeFrom = typeFrom;
41 }
The buildkey mapping from interface to the actual type is performed by UnityDefaultBehaviorExtension using the BuildKeyMappingPolicy as a container. I changed it a little to put the source type in the BuildKey.
61 private void OnRegister(object sender, RegisterTypeMappingEventArgs e)
62 {
63 context.RegisterNamedType(e.TypeFrom, e.Name);
64 context.Policies.Set<IBuildKeyMappingPolicy>(
65 new BuildKeyMappingPolicy(new NamedTypeBuildKey(e.TypeTo, e.Name, e.TypeFrom )),
66 new NamedTypeBuildKey(e.TypeFrom, e.Name));
67 }
Now I have every information I need in my PolicyInjectionStrategy. I created the following code the perform the wrapping:
7 public class PolicyInjectionStrategy : BuilderStrategy
8 {
9 public override object BuildUp( IBuilderContext context, object buildKey, object existing )
10 {
11 ITypeBasedBuildKey typeBasedBuildKey = buildKey as ITypeBasedBuildKey;
12
13 if( typeBasedBuildKey != null )
14 {
15 Type typeTo = typeBasedBuildKey.Type;
16 Type typeFrom = typeBasedBuildKey.TypeFrom;
17
18 if( typeFrom != null && typeFrom.IsInterface )
19 {
20 existing = Wrap( existing, typeFrom );
21 }
22 else if( typeTo.IsMarshalByRef )
23 {
24 existing = Wrap( existing, typeTo );
25 }
26 }
27
28 return base.BuildUp( context, buildKey, existing );
29 }
30
31
32 private static object Wrap( object existing, Type t )
33 {
34 if( existing != null )
35 {
36 existing = (new PolicyInjectorFactory()).Create().Wrap(existing, t);
37 }
38 return existing;
39 }
It first checks if a typeFrom is present and if it's an interface. If so, we can wrap the object based on this interface. If this is not the case we have a second chance by checking if the object is derived from MarshalByRefObject. If this is also not true, we just pass the received object back to the strategy chain.
The private Wrap method also contains a little trick. I'm not using the Wrap method of the PolicyInjection type, but a PolicyInjector created by a factory. I had to do this because the Wrap method of PolicyInjection does not provide a non generic overload. For generics every type has to be known at compile time and this is not the case here. The PolicyInjection type is just a little sugar over the PolicyInjector so we can easily bypass this by doing this.
The last thing you need to do is the create an extension that enlists the strategy
9 public class PolicyInjectionExtension : UnityContainerExtension
10 {
11 protected override void Initialize(ExtensionContext extensionContext)
12 {
13 extensionContext.Strategies.AddNew<PolicyInjectionStrategy>(UnityBuildStage.PostInitialization);
14 }
15 }
and register it
33 IUnityContainer container = new UnityContainer()
34 .Register<ILogger, TraceLogger>()
35 .Register<IStoplightTimer, RealTimeTimer>()
36 .AddNewExtension<PolicyInjectionExtension.PolicyInjectionExtension>();
There are probably a lot of improvements to be made on this solution and not everybody will be very happy with modifying Unity and ObjectBuilder2. But it's a start and I hope this will help you a little bit to get started.