WCF and dependency inversion using Castle Windsor

When you start to work with TDD and other Agile practices the first thing you try to apply almost everywhere in your code is the Dependency Inversion pattern because you want to invert the logic of your dependencies to make your code more testable and maintainable.

In order to accomplish this result I am using Castle Windsor, while before 2013 I was working with Microsoft Unity. I am not going to jump into the conversation “Which Inversion of Control container is better?” because it really depends on what you need to do. For years I was more than satisfied with Unity but recently I started to create complex bootstrappers for my applications and I found Windsor more flexible, that’s it! Nerd smile

How does WCF create a service instance?

First of all, in order to apply dependency inversion inside WCF we need to understand how WCF works and how it creates new service instance. I found this article on MSDN very helpful during my researches: Extending WCF.

So, this is the final result I want to obtain:

image

When you create a new service in WCF, you can specify the factory that will be in charge of creating the service instance.

This is the code you should use to specify the factory:

   1: <%@ ServiceHost Language="C#"

   2:     Factory="Raf.DependencyInjectionHostFactory"

   3:     Service="Raf.MyService" %>

Now, the factory should start a new instance of our service, or better, should use the ioc container to resolve an instance of that service.

Second step is to create a custom host that will add a new behaviour to our service, the behaviour will call the service locator (I know it’s an anti-pattern …) to inject the dependencies. In my case, Castle Windsor.

Factory

   1: public class DependencyInjectionHostFactory : ServiceHostFactory

   2: {

   3:     protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)

   4:     {

   5:         // method called when we hit a request to http:// ... youservice.svc

   6:         return new DependencyInjectionHost(serviceType, baseAddresses);

   7:     }

   8: }

Host

   1: public class DependencyInjectionHost : ServiceHost

   2: {

   3:     // omit

   4:     // ...

   5:     protected override void OnOpening()

   6:     {

   7:         // attach the behavior

   8:         Description.Behaviors.Add(new DependencyInjectionServiceBehavior());

   9:         base.OnOpening();

  10:     }

  11: }

Service behavior

   1: public class DependencyInjectionServiceBehavior : IServiceBehavior

   2: {

   3:     #region IServiceBehavior Members

   4:

   5:     public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)

   6:     {

   7:     }

   8:

   9:     public void AddBindingParameters(

  10:         ServiceDescription serviceDescription,

  11:         ServiceHostBase serviceHostBase,

  12:         Collection<ServiceEndpoint> endpoints,

  13:         BindingParameterCollection bindingParameters)

  14:     {

  15:     }

  16:

  17:

  18:     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)

  19:     {

  20:         foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)

  21:         {

  22:             var cd = cdb as ChannelDispatcher;

  23:             if (cd != null)

  24:             {

  25:                 foreach (EndpointDispatcher ed in cd.Endpoints)

  26:                 {

  27:                     ed.DispatchRuntime.InstanceProvider =

  28:                         new DependencyInjectionInstanceProvider(serviceDescription.ServiceType);

  29:                 }

  30:             }

  31:         }

  32:     }

  33:

  34:     #endregion

  35: }

So, the instance provider is able to retrieve a registration for our service using the service locator:

   1: public class DependencyInjectionInstanceProvider : IInstanceProvider

   2: {

   3:     private readonly Type serviceType;

   4:

   5:     public DependencyInjectionInstanceProvider(Type serviceType)

   6:     {

   7:         this.serviceType = serviceType;

   8:     }

   9:

  10:     public object GetInstance(InstanceContext instanceContext, Message message)

  11:     {

  12:         IServiceLocator serviceLocator = ServiceLocator.Current;

  13:

  14:         return serviceLocator.GetInstance(serviceType);

  15:     }

  16:

  17:     public void ReleaseInstance(InstanceContext instanceContext, object instance)

  18:     {

  19:         // if you container allows you to destroy instance

  20:         // you can destroy your service instance here

  21:     }

  22:

  23:     #endregion

  24: }

That’s it. Of course my container needs to know what is my service registration, and with Windsor I have two options:

   1: // option one, register the interface

   2: Component

   3:     .For<IWriteService>()

   4:     .ImplementedBy<WriteService>()

   5:

   6: // option two register the class

   7: Component

   8:     .For<WriteService>()

   9:     .ImplementedBy<WriteService>()

And of course you need to change the markup of your .svc file depending on how you want to resolve the service, with the interface or with the  class type.

Dependency Injection

Now, let’s assume that my service needs an IUnitOfWork contract, how should we do that?

First of all we need to register both types in our container, and with Windsor one of the possible options is this one:

   1: Component.For<IUnitOfWork>()

   2:             .ImplementedBy<UnitOfWork>(),

   3: Component

   4:     .For<ICommandService>()

   5:     .ImplementedBy<CommandService>(),

And my command service is constructed in this way:

   1: public class CommandService : ICommandService

   2: {

   3:     private readonly IUnitOfWork unitOfWork;

   4:

   5:     public CommandService(IUnitOfWork unitOfWork)

   6:     {

   7:         this.unitOfWork = unitOfWork;

   8:     }

   9: }

Note for purist of CQRS: I know that a command service should get a command dispatcher injected but for this blog post I guess it would not make things clear enough, so a unit of work or an IRepository would make more sense.