Windows Communication Foundation – Resolving WCF service dependencies with Unity

This series of posts will talk about Windows Communication Foundation, starting with an introduction into the technology and how to use it in you project, moving onto more advanced topics such as using an IOC container to satisfy dependencies in your services.
Posts in this series:

In this post I am going to use Microsoft Unity Inversion of Control container to resolve the dependencies for the ProductService implementation.

Most developers will already be familiar with the concept of Dependency Injection and will probably have used an IOC container such as Unity or Castle.Windsor at some point. In order to use Unity to resolve the dependencies in a service implementation a few steps must be taken to wire up Unity with WCF. This post will walk throught the steps to do this.

Adding Unity and creating the DI Wrapper

I have created a new project to hold all the DI related stuff. You may wish to put it somewhere else, which is fine. Into that project I have a added Unity via NuGet. The fisrt thing to do is to create a static wrapper for the Unity Container so we can be sure we are getting the same Unity container whenever we need to use it.

using Microsoft.Practices.Unity;

namespace WcfServiceApplication.DependencyInjection
{
    public static class DIWrapper
    {
        private static readonly IUnityContainer _container;

        static DIWrapper()
        {
           _container = new UnityContainer();   
        }

        public static IUnityContainer Container
        {
            get { return _container; }
        }
    }
}

The DIWrapper provided a static getter returning the UnityContainer. As it is a static class the constructor is guaranteed to run only once and ensures that a new UnityContainer is created. This same container will be returned whenever a call to DIWrapper.Container is made.

UnityServiceHostFactory

A service host does exactly as the name would suggest. A service such as the currect Prodcut Service can be hosted on the standard service host without any issues. Once we want to use Unity (or any other IOC container) we need to extend the ServiceHost functionality in order to resolve the dependencies in the service implementation. WCF uses a factory pattern to provide a layer of indirection between the hosting environment and the concrete type of the service required. If you don’t specify which ServiceHostFactory to use, you will get the default factory that returns an instance of the default ServiceHost.

To specify a ServiceHostFactory for a service it needs to be specified in the service .svc file like so:

<%@ ServiceHost 
    Language="C#" Debug="true" 
    Service="WcfServiceApplication.Implementation.ProductService" 
    Factory="WcfServiceApplication.DependencyInjection.WCF.UnityServiceHostFactory"
%>

If you do not specify a factory in the .svc file you will encounter the following error when trying to use the service.

“InvalidOperationException: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.”

This is because the default behavior for WCF is to call the parameteless constructor, but if you are using constructor injection for the dependency the service implementation will not have one, so WCF does not know how to instantiate the service.

Obviously this factory does not exist so we had better create it. To do so we extend System.ServiceModel.Activation.ServiceHostFactory.

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;

namespace WcfServiceApplication.DependencyInjection.WCF
{
    public class UnityServiceHostFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new UnityServiceHost(serviceType, baseAddresses);
        }
    }
}

All the factory needs to do is return a new instance of ServiceHost, so we just override CreateServiceHost to return our yet to be created new ServiceHost

UnityServiceHost

The new ServiceHost functionality is again very straight forward. System.ServiceModel is extended and a single method is overridden.

using System;
using System.ServiceModel;
using Microsoft.Practices.Unity;

namespace WcfServiceApplication.DependencyInjection.WCF
{
    public class UnityServiceHost : ServiceHost
    {
        public UnityServiceHost(Type serviceType, Uri[] baseAddresses)
            : base(serviceType, baseAddresses) { }

        public IUnityContainer Container
        {
            get { return DIWrapper.Container; }
        }

        protected override void OnOpening()
        {
            new UnityServiceBehavior(Container).AddToHost(this);
            base.OnOpening();
        }
    }
}

Inside the overridden OnOpening method a new UnityServiceBehavior is created (which we will create next) and added to the UnityServiceHost before the OnOpening method on the base ServiceHost is called.

UnityServiceBehavior

The System.ServiceModel.Description.IServiceBehavior interface provides a mechanism to extend or modify some aspect of an entire service. To use Unity with WCF we need to add some custom endpoint behaviour.

using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.Unity;

namespace WcfServiceApplication.DependencyInjection.WCF
{
    public class UnityServiceBehavior : IServiceBehavior
    {
        private ServiceHost serviceHost;

        public UnityServiceBehavior()
        {
            InstanceProvider = new UnityInstanceProvider();
        }

        public UnityServiceBehavior(IUnityContainer unity)
        {
            InstanceProvider = new UnityInstanceProvider();
            InstanceProvider.Container = unity;
        }

        public UnityInstanceProvider InstanceProvider { getset; }

        public void AddBindingParameters(
                ServiceDescription serviceDescription,
                ServiceHostBase serviceHostBase,
                Collection<ServiceEndpoint> endpoints,
                BindingParameterCollection bindingParameters) { }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (var cdb in serviceHostBase.ChannelDispatchers)
            {
                var cd = cdb as ChannelDispatcher;
                if (cd != null)
                {
                    foreach (var ed in cd.Endpoints)
                    {
                        InstanceProvider.ServiceType = serviceDescription.ServiceType;
                        ed.DispatchRuntime.InstanceProvider = InstanceProvider;
                    }
                }
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }

        public void AddToHost(ServiceHost host)
        {
            if (serviceHost != null)
            {
                return;
            }

            host.Description.Behaviors.Add(this);
            serviceHost = host;
        }
    }
}

ApplyDispatchBehavior can be used to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects. In the UnityServiceBehavior class ApplyDispatchBehavior is used to assign a custom InstanceProvider to the service endpoints.The InstanceProvider in this case is our own UnityInstanceProvider (the implementation of which is shown below).It is the InstanceProvider that will actually use Unity’s funcitonality to resolve the dependencies in the service impementation.

The behaviour of the Validate and AddBindingParameters methods does not need to change and so have empty implementations.

UnityInstanceProvider

This implementation of IInstanceProvider allow control over the instantiation of the service class. Our aim is for Unity to resolve the service type (ProductService in this example) and its dependencies.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.Unity;

namespace WcfServiceApplication.DependencyInjection.WCF
{
    public class UnityInstanceProvider : IInstanceProvider
    {
        public UnityInstanceProvider()
            : this(null) { }

        public UnityInstanceProvider(Type type)
        {
            ServiceType = type;
            Container = new UnityContainer();
        }

        public IUnityContainer Container { getset; }

        public Type ServiceType { getset; }

        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            return Container.Resolve(ServiceType);
        }

        public object GetInstance(InstanceContext instanceContext)
        {
            return GetInstance(instanceContext, null);
        }

        public void ReleaseInstance(InstanceContext instanceContext, object instance) { }
    }
}

In the UnityServiceBehavior constructor a new UnityInstanceProvider is created and the Unity Container from DIWrapper.Container is assigned as the Container. The GetInstance method then calles Container.Resolve(ServiceType) to resolve an instance of the required type. This is where Unity resolves the dependencies and returns an instance of the Service type with the dependencies satisfied. WCF can now happily use this instance for the service.

Add the dependency to the service

At present the ProductService does not have any dependencies so I will add one to a product repository from where we will return some data. The Prodcut service not looks like this:

using System.ServiceModel.Activation;
using WcfServiceApplication.Contract;
using WcfServiceApplication.Domain;
using WcfServiceApplication.Repository.Interface;

namespace WcfServiceApplication.Implementation
{
    public class ProductService : IProductService
    {
        private readonly IProductRepository productRepository;

        public ProductService(IProductRepository productRepository)
        {
            this.productRepository = productRepository;
        }

        public Product GetProductById(int productId)
        {
            return productRepository.GetProductById(productId);
        }
    }
}

Note that there is no paramaterless constructor, so this service can no longer be resolved via the standard WCF ServiceHost. I have kept the service implementation simple and just moved the logic that was there to the new repository.

using WcfServiceApplication.Domain;
using WcfServiceApplication.Repository.Interface;

namespace WcfServiceApplication.Repository
{
    public class ProductRepository : IProductRepository
    {
        public Product GetProductById(int productId)
        {
            return new Product
            {
                Id = productId,
                Name = "Product " + productId,
                Description = "A nice product"
            };
        }
    }
}

Configure Unity in Global.asax

Finally we need to configure Unity in the Global.asax of the ServiceHost. We are going to tell Unity to give us back a ProductRepository instance whenever a constructor is expecting an IProductRepository.

using System;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.Unity;
using WcfServiceApplication.DependencyInjection;
using WcfServiceApplication.Repository;
using WcfServiceApplication.Repository.Interface;

namespace WcfServiceApplication
{
    public class Global : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            ConfigureUnity();
        }

        protected void Session_Start(object sender, EventArgs e){}

        protected void Application_BeginRequest(object sender, EventArgs e){}     

        protected void Application_AuthenticateRequest(object sender, EventArgs e){}

        protected void Application_Error(object sender, EventArgs e){}

        protected void Session_End(object sender, EventArgs e){}

        protected void Application_End(object sender, EventArgs e){}

        private void ConfigureUnity()
        {
            // Configure common service locator to use Unity
            ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(DIWrapper.Container));

            // Register the repository
            DIWrapper.Container.RegisterType<IProductRepositoryProductRepository>();           
        }
    }
}

Now we are all ready to run the service. In the next post I will look at using Unity to resolve Channels for the MVC client so we can just inject the service interfaces into the MVC controller, removing the need to call the Channel factory code from the previous post each time we want a new Channel to consume a service.

Posts in this series:

Advertisements

5 Responses to Windows Communication Foundation – Resolving WCF service dependencies with Unity

  1. Pingback: An Introduction to Windows Communication Foundation – Creating a basic service « James Heppinstall: On Development

  2. Pingback: Windows Communication Foundation – Consuming a WCF service with ChannelFactory « James Heppinstall: On Development

  3. Pingback: Windows Communication Foundation – Resolving MVC client WCF ChannelFactory dependencies with Unity « James Heppinstall: On Development

  4. Looks nice, but what if i dont have Global.asax since im using a WCF Service Library ?

    Where should i ConfigureUnity() ?

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

%d bloggers like this: