Inversion of Control with WCF and Unity

Lately, I often talks with friends and colleagues about Inversion of Control (IOC) and WCF. Then, I’ve decided to publish this post and explain the necessary steps to get IoC in WCF. For this example, let’s get to use Unity ad framework for IoC.

First, the necessary components are:

  • InstanceProvider: it is the component that creates the service instance. It uses the UnityContainer;
  • ServiceBehavior: creates the InstanceProvider and allows to use it in the current context;
  • ServiceHost: handles the environment of our service. The ServiceHost configures the service for use and then it allows to apply the created ServiceBehavior instance;

We then get: UnityInstanceProvider, UnityServiceBehavior and UnityServiceHost.

UnityInstanceProvider

The first step is to create the InstanceProvider. The code is really simple:

  1: internal class UnityInstanceProvider : IInstanceProvider
  2: {
  3:     private readonly IUnityContainer container;
  4:     private readonly Type contractType;
  5: 
  6:     public UnityInstanceProvider(IUnityContainer container, Type contractType)
  7:     {
  8:         this.container = container;
  9:         this.contractType = contractType;
 10:     }
 11: 
 12:     public object GetInstance(InstanceContext instanceContext)
 13:     {
 14:         return GetInstance(instanceContext, null);
 15:     }
 16: 
 17:     public object GetInstance(InstanceContext instanceContext, Message message)
 18:     {
 19:         return container.Resolve(contractType);
 20:     }
 21: 
 22:     public void ReleaseInstance(InstanceContext instanceContext, object instance)
 23:     {
 24:         container.Teardown(instance);
 25:     }
 26: }

The first constructor’s parameters is the instance of the UnityContainer and the second is the specific endpoint contract. Both are used by the GetInstance to resolve the service’s instance. Naturally, the method could be better.

UnityServiceBehavior

The ServiceBehavior, as mentioned above, creates the InstanceProvider for the specifiv service endpoint:

  1: public class UnityServiceBehavior : IServiceBehavior
  2: {
  3:     private readonly IUnityContainer container;
  4: 
  5:     public UnityServiceBehavior(IUnityContainer container)
  6:     {
  7:         this.container = container;
  8:     }
  9: 
 10:     public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
 11:     {
 12:     }
 13: 
 14:     public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
 15:     {
 16:     }
 17: 
 18:     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
 19:     {
 20:         foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
 21:         {
 22:             foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
 23:             {
 24:                 if (endpointDispatcher.ContractName != "IMetadataExchange")
 25:                 {
 26:                     string contractName = endpointDispatcher.ContractName;
 27:                     ServiceEndpoint serviceEndpoint = serviceDescription.Endpoints.FirstOrDefault(e => e.Contract.Name == contractName);
 28:                     endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(this.container, serviceEndpoint.Contract.ContractType);
 29:                 }
 30:             }
 31:         }
 32:     }
 33: }

The constructor gets from ServiceHost the container’s instance. Then the ApplyDispatchBehavior assigns the instance to the UnityInstanceProvider with the contracts used to resolve the service instance. Finally the UnityInstanceProvider is assigned to InstanceProvider property of DispatchRuntime for each EndpointDispatcher.

UnityServiceHost

The finaly step is to create the ServiceHost:

  1: public class UnityServiceHost : ServiceHost
  2: {
  3:     private IUnityContainer unityContainer;
  4: 
  5:     public UnityServiceHost(IUnityContainer unityContainer, Type serviceType) : base(serviceType)
  6:     {
  7:         this.unityContainer = unityContainer;
  8:     }
  9: 
 10:     protected override void OnOpening()
 11:     {
 12:         base.OnOpening();
 13: 
 14:         if (this.Description.Behaviors.Find<UnityServiceBehavior>() == null)
 15:         {
 16:             this.Description.Behaviors.Add(new UnityServiceBehavior(this.unityContainer));
 17:         }
 18:     }
 19: }

The code is really simple. The ServiceHost's constructor gets the container and the service type as parameters. In the OnOpening method override the ServiceHost checks if the UnityServiceBehavior is already added to Service’s behaviors. If not, it creates the instance and pass the container’s instance to the contructor.

Utilizzo in una applicazione console self-hosted

Now we are ready. This is the sample configuration we'll use in our service:

  1: <?xml version="1.0" encoding="utf-8" ?>
  2: <configuration>
  3:   <configSections>
  4:     <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  5:   </configSections>
  6:   
  7:   <unity>
  8: 
  9:     <containers>
 10: 
 11:       <container>
 12:         <types>
 13:           
 14:           <type type="DotNetSide.WCF.IoC.Console.InnerBookService, DotNetSide.WCF.IoC.Console"
 15:                 name="inner"/>
 16: 
 17:           <type type="DotNetSide.WCF.IoC.Console.IBookService, DotNetSide.WCF.IoC.Console"
 18:                 mapTo="DotNetSide.WCF.IoC.Console.BookService, DotNetSide.WCF.IoC.Console">
 19:             <typeConfig>
 20:               <constructor>
 21:                 <param name="innerService" parameterType="DotNetSide.WCF.IoC.Console.InnerBookService, DotNetSide.WCF.IoC.Console">
 22:                   <dependency name="inner" />
 23:                 </param>
 24:               </constructor>
 25:             </typeConfig>
 26:           </type>
 27: 
 28:         </types>
 29:       </container>
 30: 
 31:     </containers>
 32:     
 33:   </unity>
 34: 
 35: </configuration>

Simply must be created an InnerBookService instance and then get it into the BookService’s constructor, an IBookService contract implementation:

  1: [ServiceContract]
  2: internal interface IBookService
  3: {
  4:     [OperationContract]
  5:     Book ReadBook(string bookId);
  6: }
  7: 
  8: class BookService : IBookService
  9: {
 10:     private readonly InnerBookService innerService;
 11: 
 12:     public BookService(InnerBookService innerService)
 13:     {
 14:         this.innerService = innerService;
 15:     }
 16: 
 17:     public Book ReadBook(string bookId)
 18:     {
 19:         return this.innerService.ReadBook(bookId);
 20:     }
 21: }
 22: 
 23: class InnerBookService
 24: {
 25:     public Book ReadBook(string bookId)
 26:     {
 27:         return new Book()
 28:         {
 29:             Title = "WCF",
 30:             Description = "A book on Windows Communication Foundation"
 31:         };
 32:     }
 33: }

Finally we build the ServiceHost with the instance of the UnityContainer:

  1: var unityContainer = new UnityContainer();
  2: var configurationSection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
  3: configurationSection.Containers.Default.Configure(unityContainer);
  4: 
  5: Uri serviceAddress = new Uri("http://localhost:9001/BookService");
  6: Uri mexAddress = new Uri("http://localhost:9001/BookService/mex");
  7: using (UnityServiceHost host = new UnityServiceHost(unityContainer, unityContainer.Resolve<IBookService>().GetType()))
  8: {
  9:     host.Description.Behaviors.Add(new ServiceMetadataBehavior());
 10:     host.AddServiceEndpoint(typeof(IBookService), new BasicHttpBinding(), serviceAddress);
 11:     host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), mexAddress);
 12: 
 13:     host.Open();
 14: 
 15:     System.Console.Read();
 16: 
 17:     host.Close();
 18: }

We also add a WS-MetadataExchange endpoint. In this way we can create our client and try to call the service.

Actually, the UnityServiceHost is not necessary but helps us to encapsulate the behavior creation. We can also write:

  1: using (ServiceHost host = new ServiceHost(unityContainer.Resolve<IBookService>().GetType()))
  2: {
  3:     host.Description.Behaviors.Add(new UnityServiceBehavior(unityContainer));
  4:     // ...
  5: }
  6: 

Feedback?

bye

kick it on DotNetKicks.com

Published Tuesday, March 24, 2009 12:11 AM by fabioc
Filed under: ,

Comments

# re: Inversion of Control with WCF and Unity

Monday, March 23, 2009 10:43 PM by Jason

Hello,

Do you know if Unity will be replaced with MEF?

# Inversion of Control with WCF and Unity - Fabio Cozzolino

Tuesday, March 24, 2009 8:47 AM by DotNetKicks.com

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# Inversion of Control with WCF and Unity (Part II)

Tuesday, March 24, 2009 3:41 PM by Fabio Cozzolino

This post is based on the first Inversion of Control with WCF and Unity . In the last post we have seen

# re: Inversion of Control with WCF and Unity

Wednesday, March 31, 2010 2:50 AM by Kalyan

Is is possible to get the complete solution for download, as I am working on wcf and IoC

# re: Inversion of Control with WCF and Unity

Tuesday, April 06, 2010 12:07 PM by Chris P

Great post, can you please provide a download link for the sample code? Thanks again!

# re: Inversion of Control with WCF and Unity

Tuesday, January 18, 2011 1:07 PM by R. Kevin Burton

I would like to register a chain of methods to be called before and after a target imploementation. This post comes close to interception but would you mind providing a little more feedback on implementing multiple interception methods?

# Vanilla Yet Composable HTTP Services With WCF 4 and Windsor | Howard Dierking

Pingback from  Vanilla Yet Composable HTTP Services With WCF 4 and Windsor | Howard Dierking

# Composable HTTP Services With WCF 4 and Windsor | Eagle081183&#039;s Blog

Pingback from  Composable HTTP Services With WCF 4 and Windsor | Eagle081183&#039;s Blog

# Explicitly calling a service constructor when hosting a WCF web service on IIS - Programmers Goodies

Pingback from  Explicitly calling a service constructor when hosting a WCF web service on IIS - Programmers Goodies

# Unity does not intercept WCF Service calls | trouble86.com

Tuesday, November 01, 2011 12:32 PM by Unity does not intercept WCF Service calls | trouble86.com

Pingback from  Unity does not intercept WCF Service calls | trouble86.com

Leave a Comment

(required) 
(required) 
(optional)
(required)