3

I am using Ninject together with ASP.NET MVC 4. I am using repositories and want to do constructor injection to pass in the repository to one of the controllers.

Here is my context object (EntityFramework) that implements my StatTracker interface:

public class StatTrackerRepository : IStatTrackerRepository
{
    private GolfStatTrackerEntities _ctx;

    public StatTrackerRepository(GolfStatTrackerEntities ctx)
    {
        _ctx = ctx;
    }

    public IQueryable<Facility> GetFacilites()
    {
        return _ctx.Facilities;
    }
}

This is my Repository interface:

public interface IStatTrackerRepository
{ 
    IQueryable<Facility> GetFacilites();
}

Which then calls my Home Controller:

public class HomeController : Controller
{
    public IStatTrackerRepository _repo { get; set; }

    public HomeController(IStatTrackerRepository repo)
    {
        _repo = repo;
    }

    public ActionResult Index()
    {
        var facilities = _repo.GetFacilites().ToList();
        return View(facilities);
    }
}

The page loads properly, however, once the page is loaded, it immedately uses an angularjs Controller which calls the $http method:

function facilityIndexController($scope, $http) {
    $scope.data = [];
    $http({ method: 'GET', url: '/api/facility' }).
        success(function(result) {
            angular.copy(result.data, $scope.data);
        }).error(function() {
            alert("Could not load facilities");
        });
}

...which calls the following API controller:

public class FacilityController : ApiController
{
    public IStatTrackerRepository _repo { get; set; }
    public GolfStatTrackerEntities ctx { get; set; }

    //public FacilityController()
    //{
    //    _repo = new StatTrackerRepository(ctx);
    //}

    public FacilityController(IStatTrackerRepository repo)
    {
        _repo = repo;
    }

    public IEnumerable<Facility> Get()
    {
        var facilities = _repo.GetFacilites().ToList();
        return facilities;
    }
}

....where it falls into the error function of the angular $http call because the FacilityController(IStatTrackerRepository repo) is never ran.

I have tried using a parameterless contstructor that instantiates a StatTrackerRepository(ctx) for FacilityController(), however, I get a NullReferenceException when I do so.

My Ninject config is as follows:

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 NinjectResolver(kernel);
        return kernel;
    }
    catch
    {
        kernel.Dispose();
        throw;
    }
}


private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<GolfStatTrackerEntities>().To<GolfStatTrackerEntities>().InRequestScope();
    kernel.Bind<IStatTrackerRepository>().To<StatTrackerRepository>().InRequestScope();            
}

I'm not sure if this is something wrong with Ninject or if there is an issue with how I am implementing Ninject. The injection seems to be working on the initial load of the Home view, however, when it uses angular to call the API, there is a disconnect with Ninject.

Please help.

Christos
  • 53,228
  • 8
  • 76
  • 108
MTL323
  • 177
  • 3
  • 14

1 Answers1

5

We ended up using a similar configuration on one of our older projects and realized that we needed to add a little more infrastructure code to our MVC/WebApi App:

NinjectDependencyScope.cs

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Web.Http.Dependencies;
using Ninject;
using Ninject.Syntax;

namespace YourAppNameSpace
{
    public class NinjectDependencyScope : IDependencyScope
    {
        private IResolutionRoot _resolver;

        internal NinjectDependencyScope(IResolutionRoot resolver)
        {
            Contract.Assert(resolver != null);
            _resolver = resolver;
        }

        public void Dispose()
        {
            var disposable = _resolver as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }

            _resolver = null;
        }

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

            return _resolver.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            if (_resolver == null)
            {
                throw new ObjectDisposedException("this", "This scope has already been disposed");
            }

            return _resolver.GetAll(serviceType);
        }
    }
}

NinjectDependencyResolver.cs

using System.Web.Http.Dependencies;
using Ninject;

namespace YourAppNameSpace
{
    public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
    {
        private readonly IKernel _kernel;

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

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

Then we added the following to the NinjectWebCommon.cs file:

public static void RegisterNinject(HttpConfiguration configuration)
        {
            // Set Web API Resolver
            configuration.DependencyResolver = new NinjectDependencyResolver(Bootstrapper.Kernel);

        }

And then the following to Global.asax.cs file, Application_Start method:

NinjectWebCommon.RegisterNinject(GlobalConfiguration.Configuration);
BlakeH
  • 3,354
  • 2
  • 21
  • 31
  • Where would be the best place to add these classes or do they already exist within the Ninject packages? I have the NinjectWebCommon.cs and Global.asax.cs but I am unfamiliar with the previous .cs files. – MTL323 Apr 01 '14 at 16:02
  • They did not exist. We added them to the mvc/webapi project. – BlakeH Apr 01 '14 at 16:07
  • 3
    @MTL323, you should note that Web API 2 projects can utilize the following nuget package: https://www.nuget.org/packages/Ninject.Web.WebApi/3.2.0 and you won't have to create these classes – BlakeH Apr 01 '14 at 16:40
  • 2
    Adding the Ninject.Web.WebApi package resolved the issue that I was having with the API controller. Thank you! – MTL323 Apr 02 '14 at 02:45