I needed to make a WCF project more unit testable by isolating dependencies. For the most part with nice Ninject extensions for WCF it wasn't too difficult, but I had a couple of hicups due to the fact that as with this and many other open source projects, Ninject WCF extension project wiki, StackOverflow answers and the latest code were a bit out of sync. In addition to that my project had behavior extension and I also wanted to add as little of extra code as possible.

My solution has three projects, WCF Service library, service host and unit tests. Service library is where the most work happens while service host has one .svc file

<%@ ServiceHost Language="C#" Service="PaymentGateway.PaymentService" %>  

I wanted to inject dependencies into service class with somethig like

    public class PaymentService : IPaymentService
    {
        private readonly ILog _log;
        private readonly IRepository _repository;
        private readonly IBackend _backend;

        public PaymentService(IRepository repository, ILog log, IBackend backend)
        {
            _log = log;
            _repository = repository;
            _backend = backend;
        }        
        /// ...
     }

These were my steps to make it happen.

Add Ninject and NinjectExtension.Wcf (which pulls Ninject.Web.Common) into service library and unit test projects. There's no need adding them to the host project.

Then subclass NinectModule:

    public class ServiceModule : NinjectModule
    {
        public override void Load()
        {
            Kernel.Bind<IRepository>().To<Repository>();
            log4net.Config.XmlConfigurator.Configure(); 
            Kernel.Bind<ILog>().ToMethod(ctx => LogManager.GetLogger(typeof(PaymentService)));
            Kernel.Bind<IBackend>().To<Backend>();
        }
    }

Subclass NinjectServiceHostFactory

class ServiceHostFactory : NinjectServiceHostFactory  
    {
        public ServiceHostFactory()
        {
            var kernel = new StandardKernel(new ServiceModule());
            kernel.Bind<ServiceHost>().To<NinjectServiceHost>();
            SetKernel(kernel);            
        }
    }

Then add this section to the web.config of the host project:

      <serviceHostingEnvironment>
          <serviceActivations>
              <add
              factory="PaymentGateway.ServiceHostFactory"
              service="PaymentGateway.Service"
              relativeAddress="PaymentServiceHost.svc"/>
          </serviceActivations>
      </serviceHostingEnvironment>

This should get Ninject functioning and dependencies injected when browsing .svc file. However, there is a problem.

I have custom behavior extension

      <extensions>
          <behaviorExtensions>
              <add name="PaymentGateway" type="PaymentGateway.Extensions.PaymentBehaviorExtension, PaymentGateway, Version=1.0.0.0, Culture=neutral" />
          </behaviorExtensions>
      </extensions>

which creates a service behavior

    public class PaymentBehaviorExtension : BehaviorExtensionElement
    {
        private const string LogTrafficPropertyName = "LogTraffic";

        [ConfigurationProperty(LogTrafficPropertyName, IsRequired = false)]
        public bool LogTraffic
        {
            get
            { 
                return (bool)base[LogTrafficPropertyName];              
            }

            set
            { 
                base[LogTrafficPropertyName] = value;
            }
        }    

        public override Type BehaviorType
        {
            get { return typeof(PaymentServiceBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new PaymentServiceBehavior(this.LogTraffic);
        }
    }​

    public class PaymentServiceBehavior : IServiceBehavior, IDispatchMessageInspector
    {
        /// ...
    }    

Ninject WCF extensions allows for custom behavior

<system.serviceModel>  
...
  <extensions>
    <behaviorExtensions>
      <add name="yourBehaviorName" type="Ninject.Extensions.Wcf.BaseNinjectBehaviorExtensionElement+NinjectBehaviorExtensionElement`1[[YourAssembly.YourBehavior, YourAssembly]], Ninject.Extensions.Wcf" />
    </behaviorExtensions>
  </extensions>
...
</system.serviceModel>

However, since in my case I have not a service behavior but a behavior extension which creates service behavior, that wasn't working. My first takeaway was to make my behavior extension to derive from Ninject type

    public class PaymentBehaviorExtension : BaseNinjectBehaviorExtensionElement.NinjectBehaviorExtensionElement<PaymentServiceBehavior>
    {
        // ..
    }    

The next hurdle was in unit testing. I wanted to start my host during integration testing. There is a sample in Ninect WCF extension with NinjectSelfHostBootstrapper. I got it working but could not find how to inject my custom behavior. I think it is not supported. Here's the code that I ended up with instead

    [TestFixture]
    public class RealHostTests
    {
        private NinjectServiceHost<PaymentService> _host;
        private Uri _baseAddress = new Uri("http://localhost:8733/Design_Time_Addresses");
        private IPaymentService _client;
        private IKernel _kernel;

        [SetUp]
        public void Setup()
        {
            // Init server
            var binding = new BasicHttpBinding();
            _kernel = new StandardKernel();
            _kernel.Bind<IRepository>().To<Repository>();
            log4net.Config.XmlConfigurator.Configure();
            _kernel.Bind<ILog>().ToMethod(ctx => LogManager.GetLogger(typeof(PaymentService)));
            _kernel.Bind<IBackend>().To<Backend>();

            _host = _kernel.Get<NinjectServiceHost<PaymentService>>();            
            _host.AddServiceEndpoint(typeof(IQpayService), binding, _baseAddress);            
            _host.Description.Behaviors.Add(new PaymentServiceBehavior(true));
            _host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
            _host.Open();

            // Init client            
            var factory = new ChannelFactory<IPaymentService>(binding);
            _client = factory.CreateChannel(new EndpointAddress(_baseAddress));
        }        

        [TearDown]
        public void TearDown()
        {            
            _host.Close();

            // Disposing kernel may randomly give "Error loading Ninject component ICache"
            //_kernel.Dispose();
        }

I also found that disposing Ninject kernel causes random unit test failures and I had to just close the host but keep kernel running.