Thirteen Days a Week

  Home  |   Contact  |   Syndication    |   Login
  23 Posts | 0 Stories | 15 Comments | 0 Trackbacks

News

Archives

Post Categories

So you’ve written your business and data layer classes such that they support dependency injection via constructor parameters.  You’ve written a bunch of unit tests around them, achieved 100% code coverage and even used mocks for your dependencies.  Awesome, right?  Now you want to stand up some WCF services in front of that super unit tested business layer of yours.  Your new WCF services are going to have a dependency on those business layer objects, right?  How are you going to get around that?  Well, you could use a dependency injection container like Unity, NInject, StructureMap, etc.  But wait, now your WCF service classes have a dependency on whatever DI container you’re going to use.  That means you’re going to have to bootstrap that container in all of your unit tests for your WCF services.  What else can a developer do, right?  I mean, WCF service implementation classes have to have a default constructor, right?  It’s not long you can do constructor injection on a WCF service, right?  Wrong!  As it turns out, using some of the WCF extensibility points, it’s not too hard at all to achieve constructor injection with WCF.

WCF provides us an interface, IInstanceProvider, which can be used to control the instantiation of service instances.  This is a perfect place to put our calls into Unity or some other DI container.  An IInstanceProvider that returns service instances from a Unity container looks like this:

  1: using System;
  2: using System.Configuration;
  3: using System.Reflection;
  4: using System.ServiceModel;
  5: using System.ServiceModel.Channels;
  6: using System.ServiceModel.Dispatcher;
  7: using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
  8: using Microsoft.Practices.Unity;
  9: using Microsoft.Practices.Unity.Configuration;
 10: using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.Unity;
 11: 
 12: namespace WcfTechTransfer.Implementation.Hosting
 13: {
 14:     public class UnityInstanceProvider : IInstanceProvider
 15:     {
 16:         private readonly Type serviceType;
 17:         private readonly IUnityContainer container;  // TODO:  Configure your Unity container
 18: 
 19:         public UnityInstanceProvider(Type serviceType)
 20:         {
 21:             this.serviceType = serviceType;
 22:         }
 23: 
 24:         #region IInstanceProvider Members
 25: 
 26:         public object GetInstance(InstanceContext instanceContext, Message message)
 27:         {
 28:             return container.Resolve(serviceType);  // This is it, the one and only call to Unity in the entire solution!
 29:         }
 30: 
 31:         public object GetInstance(InstanceContext instanceContext)
 32:         {
 33:             return GetInstance(instanceContext, null);
 34:         }
 35: 
 36:         public void ReleaseInstance(InstanceContext instanceContext, object instance)
 37:         {
 38:             if (instance is IDisposable)
 39:                 ((IDisposable)instance).Dispose();
 40:         }
 41: 
 42:         #endregion
 43:     }
 44: }
 45: 

The IInstanceProvider implementation is pretty straight forward.  We just need to provide a constructor with a parameter for the service type.  That’s what we pass into Unity to get our service instance back.

Now that you have your IInstanceProvider, you need to wire it up to each endpoint’s dispatch runtime.  This can be accomplished through a service behavior like so:

  1: using System;
  2: using System.Collections.ObjectModel;
  3: using System.Linq;
  4: using System.ServiceModel;
  5: using System.ServiceModel.Channels;
  6: using System.ServiceModel.Description;
  7: using System.ServiceModel.Dispatcher;
  8: 
  9: namespace WcfTechTransfer.Implementation.Hosting
 10: {
 11:     public class UnityInstanceProviderServiceBehavior : IServiceBehavior
 12:     {
 13:         #region IServiceBehavior Members
 14: 
 15:         public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
 16:         {
 17:         }
 18: 
 19:         public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
 20:         {
 21:             serviceHostBase.ChannelDispatchers.ToList().ForEach(channelDispatcher =>
 22:             {
 23:                 ChannelDispatcher dispatcher = channelDispatcher as ChannelDispatcher;
 24: 
 25:                 if (dispatcher != null)
 26:                 {
 27:                     dispatcher.Endpoints.ToList().ForEach(endpoint =>
 28:                     {
 29:                         endpoint.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(serviceDescription.ServiceType);
 30:                     });
 31:                 }
 32:             });
 33:         }
 34: 
 35:         public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
 36:         {
 37:         }
 38: 
 39:         #endregion
 40:     }
 41: }

 

Next you need to add that new service behavior to your service.  This can be done through a custom service host:

 

  1: using System;
  2: using System.ServiceModel;
  3: 
  4: namespace WcfTechTransfer.Implementation.Hosting
  5: {
  6:     public class UnityServiceHost : ServiceHost
  7:     {
  8:         public UnityServiceHost()
  9:             : base()
 10:         {
 11:         }
 12: 
 13:         public UnityServiceHost(Type serviceType, params Uri[] baseAddresses)
 14:             : base(serviceType, baseAddresses)
 15:         {
 16:         }
 17: 
 18:         protected override void OnOpening()
 19:         {
 20:             this.Description.Behaviors.Add(new UnityInstanceProviderServiceBehavior());
 21:             base.OnOpening();
 22:         }
 23:     }
 24: }
 25: 

 

Again, pretty straight forward stuff here.  We’re just overriding the ServiceHost’s OnOpening() method and adding a new instance of our service behavior to the behaviors collection.

Finally, the last piece to the puzzle, a custom ServiceHostFactory that will return instances of your custom ServiceHost:

  1: using System;
  2: using System.ServiceModel;
  3: using System.ServiceModel.Activation;
  4: 
  5: namespace WcfTechTransfer.Implementation.Hosting
  6: {
  7:     public class UnityServiceHostFactory : ServiceHostFactory
  8:     {
  9:         protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
 10:         {
 11:             return new UnityServiceHost(serviceType, baseAddresses);
 12:         }
 13:     }
 14: }
 15: 

 

Since you have a custom ServiceHostFactory, if you’re hosting in IIS, you’ll need to reference this ServiceHostFactory in your .svc file, or, if you’re using .Net 4.0 and taking advantage of the new file-less activation, reference the ServiceHostFactory in your web.config like so:

  1: <!-- Using configuration based activation so we don't need to have .svc files -->
  2: <serviceActivations>
  3:   <add factory="WcfTechTransfer.Implementation.Hosting.UnityServiceHostFactory"
  4:        service="WcfTechTransfer.Implementation.DocumentService"
  5:        relativeAddress="DocumentService.svc" />
  6: </serviceActivations>

 

That’s all there is to it.  Now you just need to update your Unity configuration, register your WCF service contract and implementation, along with any dependencies they have.  Of course the code here uses Unity as the DI container, but there’s no reason you couldn’t do the same thing with any other container.

posted on Wednesday, December 01, 2010 8:37 PM

Feedback

# re: Dependency Injection and WCF Services 2/16/2011 10:38 AM Tim
Cool stuff, but i always get

The type name 'ServiceHostFactory' could not be found in the namespace 'System.ServiceModel.Activation'. This type has been forwarded to assembly 'System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' Consider adding a reference to that assembly.

I referenced both system.servicemodel and system.servicemodel.activation for .NET 4.0

Any idea?

# re: Dependency Injection and WCF Services 3/2/2011 5:49 PM Keith Hilton
Could you please post the other details of this implementation. I can't seem to find one COMPLETE example of how to use Unity with WCF, everyone always leaves a couple of things (details) out. See: "Now you just need to update your Unity configuration, register your WCF service contract and implementation, along with any dependencies they have." I'm relatively new to Unity & WCF so any more information you can provide would be extremely appreciated.
Thank You for the great information you've provided !!!
Keith Hilton

# re: Dependency Injection and WCF Services 3/18/2011 4:45 PM Chris Lamont
Looks Great, and I got it working with no modifications.

How do you cleanly control the bindings? In config, or in code?

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: