Getting started with Ninject
Asked Answered
E

3

7

I watched the first 2 beginner tutorials for Ninject on dimecasts.net. Now, I want to use Ninject 2.2 in ASP.NET MVC 3. I want a view with a mocked out Model. I get object reference not set to an instance of an object when calling my service;

    public class HomeController : Controller
    {
        private readonly IMilestoneService _service;

        public HomeController()
        {
        }

        HomeController(IMilestoneService service)
        {
            _service = service;
        }

        public ActionResult Index()
        {
            ViewBag.Message = "Change Request System";

            return View();
        }

        public ActionResult About()
        {
            return View();
        }

        #region Partial views
        public ActionResult Milestone()
        {
            var result = _service.GetMileStones();//OBJECT REF ERROR
            return View(result);
        }
        #endregion
    }

//####GLOBAL.ASAX
//By using the NinjectHttpApplication, it automatically takes care of controllers, starting up mvc, etc.
//Ninject.Web.Mvc
public class MvcApplication : NinjectHttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

    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 = UrlParameter.Optional } // Parameter defaults
        );

    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        //StartNinject();
    }

    #region Inversion of Control

    protected override IKernel CreateKernel()
    {
        return Container;
    }

    static IKernel _container;
    public static IKernel Container
    {
        get
        {
            if (_container == null)
            {
                _container = new StandardKernel(new SiteModule());
            }
            return _container;
        }
    }

    internal class SiteModule : NinjectModule
    {
        public override void Load()
        {
            //Set up ninject bindings here.
            Bind<IMilestoneService>().To<MileStoneService>();
        }
    }
    #endregion
}

I'm using Razor, he's the milestone partial view

@foreach (var item in Model)
{
    <div>item.Name</div>
}

Finally, the Home view Index

@{
    ViewBag.Title = "Home Page";
}

<h2>@ViewBag.Message</h2>
<p>
   @Html.Action("Milestone");
</p>

Edit 11/20/2013

Note that Ninject has since released version 2.0. The changes are nicely outlined on their site. Of Note StandardModule is now NinjectModule and namespace Ninject.Core no longer exists. I was able to replace it with just Ninject.

Embryology answered 17/2, 2011 at 16:28 Comment(6)
Show code of your ascx file or the code where you did the binding. The problem seems to be that ninject is not binding an instance to the interface.Azriel
and show how the mvcapplication class is declared please.Azriel
Updated with the partial view, no ascx files i'm using razor engine. The binding code is already there under the ServiceModule class. I don't know what you mean by "show how Mvcapplication class is declared"....maybe thats where the problem is.Embryology
Is readonly on _service really necessary?Inventive
No, but it's appropriate if you want to set that property once and not have it change again. I almost always use readonly on private vars that hold injected dependencies.Riviera
Please replace <div>item.Name</div> to <div>@item.Name</div>Standice
R
16

There is an issue with your controller class, the constructor with the dependency is private. Your controller should look like:

public class HomeController : Controller
{
    private readonly IMilestoneService _service;

    public HomeController(IMilestoneService service)
    {
        _service = service;
    }

}

Don't even include a public parameterless constructor, it isn't even valid, your class needs that dependency to function.

In fact, I also insert a null check against that dependency in the constructor just to be sure my class is valid on construction:

public class HomeController : Controller
{
    private readonly IMilestoneService _service;

    public HomeController(IMilestoneService service)
    {
        _service = service;
        Enforce.NotNull(() => _service); // lambda to auto-magically get variable name for exception
    }

}

There also may be an issue with your MvcApplication class.

Instead of protected void Application_Start(), there is a different function you can override, protected override void OnApplicationStarted()

This is where your calls to setup routing should go:

public class MvcApplication : NinjectHttpApplication
{

    public override void Init()
    {
        base.Init();
        Mappers.Initialize();
    }

    protected override Ninject.IKernel CreateKernel()
    {
        return Ioc.Initialize();
    }

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

    public static void RegisterRoutes(RouteCollection routes) 
    {
        Routing.RegisterRoutes(routes);
        //RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
    }
}

Of course, if you are already calling Application_Start that's fine too, but I didn't see it in the OP.

Riviera answered 17/2, 2011 at 17:17 Comment(5)
did you catch the part about the changing that private constructor to public?Riviera
Now ninject is throwing exception :( : Error activating HomeController using implicit self-binding of HomeController No constructor was available to create an instance of the implementation type.Embryology
So, wait, I see you accepted - is it working then? If not, we'll get you sorted and then it will all be gravy.Riviera
No problem. Once these little kinks are worked through it should be smooth sailing. First time's always the toughest. ;-)Riviera
LOL! I didn't see the private constructor.Azriel
A
7

Try this in your global.asax file:

//By using the NinjectHttpApplication, it automatically takes care of controllers, starting up ninject, etc.
//Ninject.Web.Mvc
public class MvcApplication : NinjectHttpApplication
{
    //Your other stuff here. No need to call StartNinject().

    #region Inversion of Control

    protected override IKernel CreateKernel()
    {
        return Container;
    }

    static IKernel _container;
    public static IKernel Container
    {
        get
        {
            if (_container == null)
            {
                _container = new StandardKernel(new SiteModule());
            }
            return _container;
        }
    }

    internal class SiteModule : NinjectModule
    {
        public override void Load()
        {
            //Set up ninject bindings here.
            Bind<IMilestoneService>().To<MileStoneService>();
        }
    }
    #endregion
}
Azriel answered 17/2, 2011 at 16:44 Comment(7)
I can't resolve NinjectHttpApplication. I only have a reference to Ninject and NinjectAdapter. I saw people talking about Ninject.Web, but this was not included in my download (.NET 4.0 version). I thought this was because 2.2 didnt need Ninject.Web anymore. Any ideas?Embryology
P.Brian: See the link in my answer. You may find it easier to go with the Ninject 2.1 included with Ninject.Web.Mvc. I guess I don't have any info on Ninject 2.2 and whether or not it needs Ninject.Web.Mvc, other than to say Ninject has moved away from combining functionality in the main lib and pushing it out into extension libs, seems odd they would reverse that.Riviera
@Embryology its in a seperate download.Azriel
@Shawn Mclean @qstarin - Now I am getting runtime error http 404 (resource cant be found). I am using the class above, re-copied my RegisterRoutes etc methods. (Ninject.Web.Mvc is referenced).Embryology
@Shawn Mclean @qstarin - nevermind, override the Init() in the MvcApplication class and tell it to call base.Init() and Application_Start() and I'm back to the same object reference error we started with.Embryology
I stuck a breakpoint in HomeController(ImilestoneService service). It never gets called...only the default constructor is called.Embryology
@P.Brian: See my additional answer.Riviera
R
4

I believe if Ninject couldn't bind that interface, you'd get a binding error. This makes me think Ninject is not instantiating your controller.

Have you included Ninject.Web.Mvc?

Riviera answered 17/2, 2011 at 16:47 Comment(2)
Sorry, I forgot to show this part in my answer to your other question.Riviera
Ha, nope. Sure didnt. I thought it would be part of the download from the main site. Guess not!Embryology

© 2022 - 2024 — McMap. All rights reserved.