Using Ninject with WCF Services

Download the code for this post.

Update: This post is based on a older version of Ninject WCF Extensions. For an example of using the new version with REST support, see this post.

In my post on the Onion Architecture I highlight the use of Dependency Injection to loosen the coupling between application components.  In an ASP.NET MVC application, it is possible to use repositories directly from controllers, but it may be desirable to place a WCF services façade over the data access layer, so that other kinds of clients, such as Silverlight or WPF, won’t directly access the database.  This is commonly referred to as an n-tier application architecture.

For a service type to rely on a DI container for a repository interface, it would likely have a constructor that accepts an I_X_Repository parameter.

public class GreetingService : IGreetingService {
    private IGreetingRepository _greetingRepo;

    public GreetingService(IGreetingRepository greetingRepo)
    {
        _greetingRepo = greetingRepo;
    }

    public string Hello()
    {
        return _greetingRepo.GetGreeting();
    }
}

However, using this service type will result in an error: “The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor.”

service-error

To remedy this, you can use a custom instance provider to obtain the GreetingService from a DI container.  Thankfully, there is a NuGet package available that provides this service: Ninject.Extensions.Wcf.

ninject-wcf

To use this for a non-web host, set the KernelContainer’s Kernel property to an kernel initialized with a Ninject module that binds your types and interfaces.  Then use NinjectServiceHost in lieu of ServiceHost.

class Program {
    static void Main(string[] args)
    {
        // Init Ninject IKernel kernel = new StandardKernel(new HelloModule());
        KernelContainer.Kernel = kernel;

        // Create service host using (var host = new NinjectServiceHost(typeof(GreetingService),
            new Uri("http://localhost:1234/GreetingService")))
        {
            host.Open();
            Console.ReadKey();
        }
    }
}

The HelloModule binds both IGreetingRepository and ServiceHost.

public class HelloModule : NinjectModule {
    public override void Load()
    {
        Kernel.Bind<IGreetingRepository>().To<GreetingRepository>();
        Kernel.Bind<ServiceHost>().To<NinjectServiceHost>();
    }
}

In the .svc file for a web host, you would set the Factory property to NinjectServiceHostFactory.

<%@ ServiceHost Service="HelloNinjectWcf.Service.GreetingService" Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>

Then add a Global.asax file that extends NinjectWcfApplication and overrides CreateKernel to return an initialized Ninject kernel.

public class Global : NinjectWcfApplication {
    protected override IKernel CreateKernel()
    {
        IKernel kernel = new StandardKernel(new HelloModule());
        return kernel;
    }
}

This works great for configuring a WCF service to use dependency injection, but there are times when you might need to spin up a WCF service for an integration test using a testing framework such as NUnit or MSTest.  This can get rather tedious, especially with DI in the mix.  For that reason, it’s convenient to use a helper class responsible for initializing both service host and client.  (Disclaimer: I have to credit my friend, Pete Young, for coming up with a helper that does this same sort of thing.)

public class NinjectServiceHelper<TServiceContract, TServiceType> : IDisposable {
    bool _disposed;

    public NinjectServiceHelper(string address, Binding binding, params Uri[] baseAddresses)
    {
        // Init Ninject service host _serviceHost = new NinjectServiceHost(typeof(TServiceType), baseAddresses);
        _serviceHost.AddServiceEndpoint(typeof(TServiceContract), binding, address);
        _serviceHost.Open();

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

    private readonly ServiceHost _serviceHost;
    public ServiceHost ServiceHost 
    {
        get {
            if (_disposed)
                throw new ObjectDisposedException("NinjectServiceHelper");
            return _serviceHost; 
        }
    }

    private readonly TServiceContract _client;
    public TServiceContract Client
    {
        get {
            if (_disposed)
                throw new ObjectDisposedException("NinjectServiceHelper");
            return _client;
        }
    }

    public void Dispose()
    {
        if (!_disposed)
        {
            ((IDisposable)_serviceHost).Dispose();
            ((IDisposable)_client).Dispose();
            _disposed = true;
        }
    }
}

The code in the Test class then becomes nice and clean.

[TestFixture]
public class GreetingServiceTests {
    private NinjectServiceHelper<IGreetingService, GreetingService> _serviceHelper;

    [TestFixtureSetUp]
    public void FixtureSetup()
    {
        // Init Ninject IKernel kernel = new StandardKernel(new HelloModule());
        KernelContainer.Kernel = kernel;

        // Create service host _serviceHelper = new NinjectServiceHelper<IGreetingService, GreetingService>
            ("http://localhost:2345/GreetingService", new BasicHttpBinding());
    }

    [TestFixtureTearDown]
    public void FixtureTearDown()
    {
        ((IDisposable)_serviceHelper).Dispose();
    }

    [Test]
    public void Greeting_Method_Should_Return_Hello()
    {
        IGreetingService client = _serviceHelper.Client;
        using ((IDisposable)client)
        {
            string greeting = client.Hello();
            Assert.That(greeting, Is.StringMatching("Hello"));
        }
    }
}

Ninject.Extensions.Wcf makes it easy to leverage Ninject for dependency injection with WCF services.  My NinjectServiceHelper makes it easier to write integration tests that spin up the service and at the same time provides a client for invoking methods on the service and writing asserts on the results.  You can download the code for this blog post here.  Enjoy.

About Tony Sneed

Sr. Software Solutions Architect, Hilti Global Application Software
This entry was posted in Technical and tagged , , . Bookmark the permalink.

11 Responses to Using Ninject with WCF Services

  1. Pingback: Using Ninject with WCF Services | Web, Programming, MS Access | Syngu

  2. Anye says:

    Hi Tony,
    If you have a service that serves many different kinds of data, so you have a whole bunch of repositories, then it seems unwieldy to rely on constructor injection for the service itself.
    Is there a way to just use the Ninject kernel to resolve an interface reference inside a service method so that they are instantiated ‘just in time’? i.e.
    public class MyService:IMyService
    {
    public void DoSomething()
    {
    IGreetingRepository repository = Kernel.Get();
    repository.DoSomething();
    }
    }

    This assumes you still had your NinjectModule containing
    Kernel.Bind().To();
    and created the kernel in the Global.asax.

    I haven’t actually tried this yet though it seems like it should work. Am I missing something?

    Most of the examples I’ve seen for Ninject + WCF are for injecting the service itself, which seems far less useful than being able to inject just the repositories specifically (unless your service methods do logic (ours don’t, they generally just flow down to the class doing the work and so we do the unit testing at that level)). Your example is great for one or two repositories but I fear the constructor would be crazy if there were a whole bunch of repositories used by the service (and it would instantiate them all up front rather than when they are needed, which depending on how commonly used they all are would either be a plus or a minus).

    • Tony Sneed says:

      @Anye,

      This is a good question and quite apropos. What you are referring to is the “Dependency Injection versus Service Locator debate, as discussed in this article by Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern. While it may seem like using an IoC container within the type would make it easier to use — just a default ctor with no need for a special service host — it actually makes the code more difficult to maintain, as described in this blog post by Mark Seemann: Service Locator is an Anti-Pattern.

      The problem is that using the container within the type hides its dependence on the container, raising the possibility someone could use the type without first initializing the container and causing runtime exceptions to take place. Injecting dependencies, such as repository interfaces, into the type’s ctor, however, makes it plain what the dependencies of the type actually are, helping ensure the type has what it needs when it needs it. Another issue is that the service locator pattern violates what Mark cleverly calls the “Hollywood Principle”: Don’t call the container, it’ll call you. Registration of services usually takes place at what is called the application’s “composition root,” which is generally on the start of the HttpApplication if you are hosting in IIS. Once the registration takes place at the root, then each service has everything it needs. This especially helps when there are dependencies between repositories. Say, for example, you are injecting IGreetingRepository, but that GreetingRepository has a ctor that accepts an ICultureRepository. The GreetingService doesn’t have to worry about those interdependencies.

      I would agree with your last point that most of the time injecting the service itself is pointless, because ServiceHost needs the service type, not the service contract interface. In terms of having a service with multiple dependencies injected via the ctor, I would suggest a higher-level interface, sort of a super-repository, that encapsulates the others. Then you would only need to inject the top-level interface. Deferred instantiation of the dependencies can be achieved with Lazy, which allows creation of instances when they are actually needed.

      Cheers,
      Tony

  3. Pingback: Ninject WCF Extensions for RESTful Services - .NET Code Geeks

  4. Eveshan says:

    Hi Tony
    Thanks for this. I have implemented your service helper, and it works well. However I have defined a custom usernamepassword validator which I also want to test, which currently falls over because I am not passing in any credentials. So where or how would I pass in the username & password credentials?

  5. Pingback: Dependency Injection in WCF Services with Ninject | Gigi Labs

  6. Prasanta says:

    Not able to download the source code

  7. Lars says:

    Hi Tony. Thanks for your helper class but your example is not working with the current release of NInject.Extension.Wcf. For example there is no KernelContainer and the NInjectServiceHost has a new constructor that needs an IServiceBehavior.

    • Tony Sneed says:

      Yes, this post is quite old. At that time, I found deficiencies with the Ninject implementation, and since then I have switched over to using Simple Injector as my DI framework, because it is much faster and well documented, and I think it also has a good WCF integration package.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.