1

I've been reading about the these two approaches to resolving dependencies and found some sample code for ninject implementations.

For service locator followed something like

 public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
 {
    IKernel kernel;

    public NinjectDependencyResolver(IKernel kernel)
        : base(kernel)
    {
        this.kernel = kernel;
    }

    public IDependencyScope BeginScope()
    {
        return new NinjectDependencyScope(kernel.BeginBlock());
    }
}

And

public class NinjectDependencyScope : IDependencyScope
{
    IResolutionRoot resolver;

    public NinjectDependencyScope(IResolutionRoot resolver)
    {
        this.resolver = resolver;
    }

    public object GetService(Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        return resolver.TryGet(serviceType);
    }

    public System.Collections.Generic.IEnumerable<object> GetServices(Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        return resolver.GetAll(serviceType);
    }

    public void Dispose()
    {
        IDisposable disposable = resolver as IDisposable;
        if (disposable != null)
            disposable.Dispose();

        resolver = null;
    }
}

And the out of the box class

    public static class NinjectWebCommon 
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        try
        {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(kernel);
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<MembersService>().To<MembersService>();
        kernel.Bind<MemberContext>().To<MemberContext>();
    }  

For composition root I followed - https://gist.github.com/paigecook/3860942

 public class NinjectKernelActivator: IHttpControllerActivator
{
    private readonly IKernel _kernel;

    public NinjectKernelActivator(IKernel kernel)
    {
        _kernel = kernel;
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        var controller = (IHttpController) _kernel.Get(controllerType);

        request.RegisterForDispose( new Release(()=> _kernel.Release(controller)));

        return controller;
    }
}

internal class Release : IDisposable
{
    private readonly Action _release;

    public Release(Action release)
    {
        _release = release;
    }

    public void Dispose()
    {
        _release();
    }
}

And made a single change to Create(..) in NinjectWebCommon.

                //GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
            GlobalConfiguration.Configuration.Services.Replace(
              typeof(IHttpControllerActivator),
                new NinjectCompositionRoot(kernel));

EDIT

Controller and service creation

public class MembersController : ApiController
{
    private readonly IMembersService _membersService;

    public MembersController(IMembersService membersService)
    {
        _membersService = embersService;
    }

    ...
}


public class MembersService : IMembersService
{
    private readonly MembersContext _context;

    public MembersService(MemberContext context)
    {
        _context = context;
    }

    ...
}

Have I correctly implemented the Composition Root? I don't really see what the difference is between the two approaches?

Bryan
  • 4,239
  • 4
  • 44
  • 62
  • It looks more or less good, but really lacks your real use-cases, how you use both in controllers. – Red Jan 26 '16 at 09:23
  • I think you should have a look at some of Mark Seemans blog post, notably: http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/ . Your code is lacking the Service-Locator specific "request instead of inject" approach which litters the code base. Well, you've not provided enough code to assess it properly, so I may be wrong. Also, I don't think this question is a good fit for SO, **maybe** it is for programms or codereview (later only if you have enough working code to present). – BatteryBackupUnit Jan 26 '16 at 09:51
  • @raderick I've added in usage in the controller and service – Bryan Jan 26 '16 at 13:06

1 Answers1

5

The difference between Composition root (which is how you should do dependency injection) and Service Locator is that composition root should be in one place of the application (as close as possible to the application's entry point). This doesn't mean that it will be invoked only once. For example in case of MVC/WebAPI good place for composition root is the controllers factory which creates controllers for every HTTP request application receives. The point is that composition root implemented in controller factory should create entire object graph (controller with all of his dependencies) that is required do handle the request such that no other dependencies need to be resolved from container separately during this request.

Service Locator on the other hand is approach where you retrieve your dependencies from service locator whenever you need them. Service locator becomes ambient context in your application (usually provides static ServiceLocator.Get<T>() method). Service Locator is the opposite of Dependency Injection because instead of injecting your dependencies you are retrieving them when you need them. This means having ServiceLocator.Get<T>() method calls all over the application code and all layers of your application have dependency on service locator. This approach has several downfalls one of them is the fact that it makes code harder to unit test, since all tests need to interact with the same global service locator class to set the fake dependencies of a class under test.

Your NinjectKernelActivator implementation of composition root is correct assuming you are not exposing IKernel elsewhere in some public static property for using it later to get dependencies that you do not inject.

Krzysztof Branicki
  • 6,187
  • 3
  • 34
  • 39