Question

I'm trying to set up Ninject for the first time. I've got an IRepository interface, and a Repository implementation. I'm using ASP.NET MVC, and I'm trying to inject the implementation like so:

public class HomeController : Controller
{
    [Inject] public IRepository<BlogPost> _repo { get; set; }

    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome to ASP.NET MVC!";

        var b = new BlogPost
                    {
                        Title = "My First Blog Post!",
                        PostedDate = DateTime.Now,
                        Content = "Some text"
                    };

        _repo.Insert(b);

        return View();
    }

    // ... etc
}

And here's Global.asax:

public class MvcApplication : NinjectHttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
        );

    }

    protected override void OnApplicationStarted()
    {
        RegisterRoutes(RouteTable.Routes);
    }

    protected override IKernel CreateKernel()
    {
        IKernel kernel = new StandardKernel(new BaseModule());
        return (kernel);
    }
}

And here's the BaseModule class:

   public class BaseModule : StandardModule
    {
        public override void Load()
        {
            Bind<IRepository<BlogPost>>().To<Repository<BlogPost>>();
        }
    }

When I browse to the Index() action, though, I get "Object reference not set to an instance of an object" when trying to use _repo.Insert(b). What am I leaving out?

Was it helpful?

Solution

Ninject 1.0 did not have MVC support out of the box. There are various ways of using MVC with Ninject 1.0 scattered around the web.

I'd recommend getting the latest code from the Ninject trunk, which includes MVC support. Then use the following as a starting point for your application:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using DemoApp.Models;
using Ninject.Core;
using Ninject.Framework.Mvc;

namespace DemoApp
{
    public class MvcApplication : NinjectHttpApplication
    {
        protected override void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );
        }

        protected override IKernel CreateKernel()
        {
            return new StandardKernel(new BaseModule(), new AutoControllerModule(Assembly.GetExecutingAssembly()));
        }
    }
}

There are a few things to highlight versus your original implementation...

  • Ninject has two implementations names NinjectHttpApplication - one in Ninject.Framework.Web and one in Ninject.Framework.Mvc. You appear to be using the former as the later contains a protected RegisterRoutes() method.
  • You need a way to give Ninject a hook into the controller creation, which is done using the ControllerBuilder. The Ninject.Framework.Mvc.NinjectHttpApplication registers the NinjectControllerFactory. You'll have to supply it yourself if using Ninject 1.0.
  • You need to register your controllers with the container. You could do it manually, but using the latest code provides and AutoControllerModule that automagically registers controllers for you!

OTHER TIPS

You need to add the AutoControllerModule to the list of modules you specify when creating the kernel, show below:

protected override IKernel CreateKernel()
{
    IKernel kernel = new StandardKernel(
                         new BaseModule(), 
                         new AutoControllerModule(Assembly.GetExecutingAssembly())
                     );
    return (kernel);
}

The AutoControllerModule is part of the MVC support in Ninject 1.x. It scans the assembly you provide to its constructor for MVC controller classes and auto-binds them. In the code, you have properly bound your repository, but Ninject is not in charge of activating your controllers. In order for your repository to be injected into an instance of your HomeController class, Ninject needs to be in charge of creating and activating controllers. Without the AutoControllerModule, MVC remains in charge of creating controllers; therefore, Ninject never gets a chance to inject any members. Once Ninject is in charge of creating and activating the controllers, the injection will occur as expected.

Think of the AutoControllerModule as finding all controllers and generating code like this (HomeController used as an example):

Bind<HomeController>.ToSelf();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top