Unity LifeTimeManager for WCF

I really love DI-frameworks. One reason is that it allows me to centralize life-time management of objects and services needed by others. Most frameworks have options to control the lifetime and allows objects to be created as Singletons, ThreadStatics, Transients (a new object everytime) etc.

I’m currently doing some work on a project where Unity is the preferred DI-framework and it’s hooked to resolve all service objects for us.

The challenge

WCF has three options for instances, PerCall, PerSession and Single (http://msdn.microsoft.com/en-us/library/system.servicemodel.instancecontextmode.aspx). IN essence this will have the following effect on dependencies injected:

PerCall All dependencies will be  resolved once per message sent to the service.
PerSession – All dependencies will be resolved once per WCF service Session.
Single – All dependencies will be resolved exactly once (Singleton).

Now why is this challenge? It’s as expected that the constructor parameters is called once per instantiation, isn’t it?

The basis of the challenge is when you want to share instances of dependencies one or more levels down. Consider this code: ´


              
  1: public class CalculationService : Contract {

              
  2:   public CalculationService(IRepository ruleRepository, 

              
  3:                             IRepository productRepository){..}

              
  4: }

This would work perfectly fine with the InstanceContextModes explained above, but what if we want to share instances of NHibernate Sessions or Entity Framework Contexts between repositories?
The default setting for most DI-Frameworks is to always resolve objects as “Transients”, which means once for each object that is dependent on them.
This is where LifeTime management comes into play by changing how the DI-Framework shares instances between dependant objects.
Unity has six “sharing-options” (from http://msdn.microsoft.com/en-us/library/ff660872(PandP.20).aspx):
TransientLifetimeManager: A new object per dependency
ContainerControlledLifetimeManager One object per unity container instance (including childrens)
HierarchicalLifetimeManager One object per unity child container
PerResolveLifetimeManager A new object per call to resolve, recursive dependencies will reuse objects.
PerThreadLifetimeManager One new object per thread
ExternallyControlledLifetimeManager Moves the control outside of Unity

As you can see we are missing our scenario. We’d like to share all dependencies of some objects across a single service instance, no matter what InstanceContextMode we choose.

The Solution

For Unity there is a good extension point that can help us. Combine that with WCF’s ability to add extensions to Instances and problem will be solved.

First we extend WCF instance context so it can hold objects created by Unity:


              
  1: public class WcfServiceInstanceExtension : IExtension

              
  2: {

              
  3:     public static WcfServiceInstanceExtension Current

              
  4:     {

              
  5:         get

              
  6:         {

              
  7:             if (OperationContext.Current == null)

              
  8:                 return null;

              
  9: 

              
 10:             var instanceContext = OperationContext.Current.InstanceContext;

              
 11:             return GetExtensionFrom(instanceContext);

              
 12:         }

              
 13:     }

              
 14: 

              
 15:     public static WcfServiceInstanceExtension GetExtensionFrom(

              
 16:                                               InstanceContext instanceContext)

              
 17:     {

              
 18:         lock (instanceContext)

              
 19:         {

              
 20:             var extension = instanceContext.Extensions

              
 21:                                            .Find();

              
 22: 

              
 23:             if (extension == null

              
 24:             {

              
 25:                 extension = new WcfServiceInstanceExtension();

              
 26:                 extension.Items.Hook(instanceContext);

              
 27: 

              
 28:                 instanceContext.Extensions.Add(extension);

              
 29:             }

              
 30: 

              
 31:             return extension;

              
 32:         }

              
 33:     }

              
 34: 

              
 35:     public InstanceItems Items = new InstanceItems();

              
 36: 

              
 37:     public void Attach(InstanceContext owner)

              
 38:     { }

              
 39: 

              
 40:     public void Detach(InstanceContext owner)

              
 41:     { }

              
 42: }

InstanceContextExtension, which get’s applied on each WCF Service Instance

              

              
  1: public class InstanceItems

              
  2: {

              
  3:     public object Find(object key)

              
  4:     {

              
  5:         if (Items.ContainsKey(key))

              
  6:             return Items[key];

              
  7: 

              
  8:         return null;

              
  9:     }

              
 10: 

              
 11:     public void Set(object key, object value)

              
 12:     {

              
 13:         Items[key] = value;

              
 14:     }

              
 15: 

              
 16:     public void Remove(object key)

              
 17:     {

              
 18:         Items.Remove(key);

              
 19:     }

              
 20: 

              
 21:     private Dictionary<object, object> Items 

              
 22:                          = new Dictionary<object, object>();

              
 23: 

              
 24:     public void CleanUp(object sender, EventArgs e)

              
 25:     {

              
 26:         foreach (var item in Items.Select(item => item.Value))

              
 27:         {

              
 28:             if (item is IDisposable)

              
 29:                 ((IDisposable)item).Dispose();

              
 30:         }

              
 31:     }

              
 32: 

              
 33:     internal void Hook(InstanceContext instanceContext)

              
 34:     {

              
 35:         instanceContext.Closed += CleanUp;

              
 36:         instanceContext.Faulted += CleanUp;

              
 37:     }

              
 38: }

InstanceItems, used by the extension to hold objects created by unity
This gives us a nice place to put created objects, it will also call dispose on any objects when the instance is closing down.
Now we need to tell Unity to use our new shiny class, this is done by first extending LifeTimeManager:

              

              
  1: public class WcfServiceInstanceLifeTimeManager : LifetimeManager

              
  2: {

              
  3:     private readonly Guid key;

              
  4: 

              
  5:     public WcfServiceInstanceLifeTimeManager()

              
  6:     {

              
  7:         key = Guid.NewGuid();

              
  8:     }

              
  9: 

              
 10:     public override object GetValue()

              
 11:     {

              
 12:         return WcfServiceInstanceExtension.Current.Items.Find(key);

              
 13:     }

              
 14: 

              
 15:     public override void SetValue(object newValue)

              
 16:     {

              
 17:         WcfServiceInstanceExtension.Current.Items.Set(key, newValue);

              
 18:     }

              
 19: 

              
 20:     public override void RemoveValue()

              
 21:     {

              
 22:         WcfServiceInstanceExtension.Current.Items.Remove(key);

              
 23:     }

              
 24: }

The LifeTimeManager that uses our WCF Extension
All that’s left now is to tell Unity when to use this LifeTimeManager instead of the default. That is done when we register the type:
container.RegisterType(new WcfServiceInstanceLifeTimeManager(), 
                                 new InjectionFactory(
                                     c => SessionFactory.CreateSession()));

In conclusion


So, DI-Frameworks are powerful to handle dependencies but sometimes they need a little nudge in the right direct. Custom LifeTimeManagement is one of those nudges you can do and both Unity and WCF helps you do that.

7 thoughts on “Unity LifeTimeManager for WCF

  1. It’s surely an interesting idea to set up extension for UoW handling.

    In the particular scenario I’m in, UoW is completly handled by a Transaction scope and NHibernate.

    I’m using FlushMode.Commit and WCF AutoComit with transactionscopes for any operations that execute anything against the database.

    Thus the need for a custom UoW handler is actually obsolete

    Reply
  2. So how do you manage the Nhibernate Sessions, for instance closing, flushing and disposing?

    Reply
  3. Can you provide a simple example? I have used a session per request in MVC, but kind of stuck since I dont know how it works with WCF. Where does the CleanUp Method reside, how do you make sure that is called when Unity is disposing of the Session?

    Thank you,

    Reply
  4. thank you very much.
    you solution solve my problem.
    多谢,十分感谢。祝你快乐

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: