Resolving Instances using Delegates in Unity

Introduction

In previous posts, I have covered bootstrapping Unity in MVC, using Unity as a DependencyResolver in MVC and using Unity in conjunction with WCF services. I am going to extend the Unity theme a little bit more and describe a technique I use to get Unity to return a instance of a WCF Channel for a requested service interface.

One of things I like about StructureMap as an IOC container is ability to use a delegate to provide the required instance for a type, as in the following code.


ChannelFactory<IAccountService> accountChannelFactory = 
                                    new ChannelFactory<IAccountService>("AccountService");

ObjectFactory.Initialize(cfg =>
{
  cfg.For<IAccountService>().Use(container 
                               => accountChannelFactory.CreateChannel());
});

Unity has no such method. When specifying an instance to return for a requested type, Unity requires a created instance to use and manages the lifetime of the object as a singleton. This means that the above functionality, where a Channel is created by a delegate to the ChannelFactory to satisfy the resolution of the IAccountService, cannot be readily implemented in Unity.

To get around this limitation, I have designed a LifetimeManager that takes as a parameter a delegate. The implementation, shown below, is simple. In the override for GetValue() the delegate is called.


public class NewInstanceLifetimeManager : LifetimeManager{
   private LifetimeManager baseManager;
   private Func<object> sourceFunc = null;

   public NewInstanceLifetimeManager(Func<object> sourceFunc, 
                                                   LifetimeManager baseManager = null){

     Contract.Requires(sourceFunc != null, "sourceFunc must be provided");
     this.sourceFunc = sourceFunc;
     this.baseManager = baseManager;
   }

   public override object GetValue(){
     object result = baseManager.GetValue();

     if (result == null){
       result = sourceFunc();

       if (baseManager != null){
         baseManager.SetValue(result);
       }
     }

     return result;
  }

  public override void RemoveValue(){
    if (baseManager != null){
      baseManager.RemoveValue();
    }
  }

  public override void SetValue(object newValue){
    if (baseManager != null){
      baseManager.SetValue(newValue);
    }
  }
}   

This seems to work pretty well as in the following:


ChannelFactory<IAccountService> accountChannelFactory = 
                                   new ChannelFactory<IAccountService>("AccountService");

container.RegisterType<IAccountService>(
               new NewInstanceLifetimeManager(()=>accountService.CreateChannel()));

Note how the NewInstanceLifetimeManager takes an underlying LifetimeManager implementation as an optional paramater. For channels I like to use a per-request context lifetime manager. I can use the NewInstanceLifetimeManager in conjunction with the ContextLifetimeManager as follows (I am using the container to resolve the ContextLifetimeManager so that the required ContextItemProvider constructor parameter is set):


ChannelFactory<IAccountService> accountChannelFactory = 
                      new ChannelFactory<IAccountService>("AccountService");

container.RegisterType<IBusinessService>(
  new NewInstanceLifetimeManager(() => businessService.CreateChannel(), 
                                 container.Resolve<ContextLifetimeManager>() ));

Conclusion

This post has covered how to extend the functionality of the Unity IOC container to enable the getting of instances using a delegate through the use of a LifetimeManager that takes a delegate as a parameter. A useful application of this technique is for the creation of WCF Channels from channel factories.

kick it on DotNetKicks.com

About these ads
This entry was posted in StructureMap, Unity and tagged , , . Bookmark the permalink.

One Response to Resolving Instances using Delegates in Unity

  1. Good post. One correction: we’ve added to Unity 2.0 a capability to use a delegate to provide the required instance for a type. It’s called InjectionFactory.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s