Common Service Host for Windows Communication Foundation

After having to write new instance providers, host factories and service behaviors for almost every new WCF project; I decided to write a simple reusable component for WCF and dependency injection and put it on codeplex so that I never had to write that again.

The idea is simple, when creating service hosts you more often then not want a centralized controlling factory that handles your dependency wiring and life time management of said dependencies. WCF requires you to add custom code to the initialization extension points.

Enter the Common Service Host. Based on the Common Service Locator interface and model it allows for a single library with classes for any DI-Framework to automatically wire up your service instances. From the codeplex documentation:

Example host configuration:

public class AppContainer : UnityContainerProvider
{
        public void EnsureConfiguration()
        {
            UnityContainer.RegisterType<IRepository, Repository>();
        }
} 

Example self-hosted usage:

using(var host = new CommonServiceHost<AppContainer>())
{
    host.Open();
}

Example usage for a .svc file:

<%@ ServiceHost Language="C#" 
      Service="Sogeti.Guidelines.Examples.Service1" 
      Factory="Sogeti.Guidelines.WCF.Hosting.CommonServiceHostFactory`1
	[[Sogeti.Guidelines.Examples.AppContainer,
 Sogeti.Guidelines.Examples.Service]], Sogeti.Guidelines.WCF.Hosting" %>

 

Included providers in the current release for Unity and spring.net

Get your copy here: http://commonservicehost.codeplex.com

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:

PerCallAll 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<Rule> ruleRepository, 
  3:                             IRepository<Product> 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<InstanceContext>
  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<WcfServiceInstanceExtension>();
 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<ISession>(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.