Ninject.MVC3, Nuget, WebActivator oh my
Asked Answered
P

2

14

I want to setup Ninject to do a simple test, as well as demonstrate the ease-of-setup using Nuget. I want to resolve a sample service.

public interface ITestService
{
    string GetMessage();
}
public class TestService : ITestService 
{
    public string GetMessage() { return "hello world"; }
}

I run the NuGet Install-Package NinjectMVC3 .... it nicely drops NinjectMVC3.cs into my App_Start folder, decorated with some WebActivator attributes to get it all loaded.

Next I add my binding in the NinjectMVC3.RegisterServices method:

private static void RegisterServices(IKernel kernel)
{
   kernel.Bind<ITestService>().To<TestServiceOne>();
}

Now I want to 'use' Ninjet to resolve my ITestService.

public ActionResult Index()
{
  //[Ninject, give me the service I need]
  ITestService service = ??? 

  ViewBag.Message = service.GetMessage();
  return View();
}

Is there another part to setting up Ninject? Do I need to provide a resolver?

What is the code I need to resolve my ITestService.

thanksasking help »

** * * * * * * * * * * * Update: * * * * * * * * * * * * * * * * **

Thanks for the great responses regarding 'controller constructor' injection. Simply adding a constructor with the ITestServcice as a param .... BAMM !!!

private ITestService _service;

public HomeController(ITestService service)
{
  _service = service
}
public ActionResult Index()
{
  ViewBag.Message = _service.GetMessage();
  return View();
}

Now what is the ideal solution for, when I need to get the Kernel directly.

var kernel = ... // Go grab the kernel from ????? (thanks Judah).
ITestService service = kernel.Get<ITestService>();

I can see the NinjectMVC3 class creates the Kernel, but does not hold or expose a reference to it, nor can I find a obvious class/method to 'get the kernel'.

I assume thee is a Ninject way to get it, but not sure.

** * * * * * * * * * * * (Final) Update: * * * * * * * * * * * * * * * * **

Thanks again for the answers and comments ....

Correction: The NinjectMVC3 class creates the Kernel, and does hold reference to the 'Bootstrapper', which as a IKernel on it.

So I added a 'resolve' method to the App_Start/NinjectMVC3 class ... works great.

public static class NinjectMVC3 /// created by the NinjectMVC3 NuGet  Packagae
{
   // add method to provide a global resolver.   
   public static T Resolve<T>()
   {
       return bootstrapper.Kernel.Get<T>();
   }
}
Paresh answered 15/3, 2011 at 16:48 Comment(1)
This is certainly a matter of opinion, but the your NinjectMVC3.Resolve<T> static method is an example of the service locator anti-pattern. Generally speaking, dependency injection should be a "tell, don't ask" kind of thing. Mark Seemann discusses this on his blog, which might help clarify things a bit. blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspxFungiform
S
4

Add the ITestService as a constructor parameter to your controller:

private ITestService service;

public MyController(ITestService service)
{
   this.service = service;
}

public ActionResult Index()
{
  ViewBag.Message = this.service.GetMessage();
  return View();
}

Ninject will automatically inject the ITestService into your controller. Then use the service field inside your Index method.


Alternately, if you don't want Ninject to inject into your controller constructor, you can keep around the kernel you create, then inside your Index method, you call kernel.Get<ITestService>() to grab an instance:

public ActionResult Index()
{
  var kernel = ... // Go grab the kernel we created back in app startup.
  ITestService service = kernel.Get<ITestService>();

  ViewBag.Message = service.GetMessage();
  return View();
}

Have a look at Ninject dependency inject for controllers in MVC3.

Stringent answered 15/3, 2011 at 16:59 Comment(3)
Thank-you, that makes sense. Now what would a good practice be for keeping the kernel around? Use a singleton as a global store?Paresh
Personally, I have a static class called Dependency, with a single method: Get<T>. That internally calls the kernel's Get method. Consuming code then looks like: Dependency.Get<IFoo>()Stringent
I would consider using the [Inject] parameter on the property instead of either a reference to the kernel, or the parameter-in-constructor approach. Adding constructors to your controllers will make for more verbose code if you have an interface on a base class that has to be passed in to every inherited constructor. ninject.codeplex.com/wikipage?title=Injection%20PatternsTempered
P
16

Steps:

  1. Create a new ASP.NET MVC 3 project
  2. Install the NuGet package from the Package Console: Install-Package Ninject.MVC3
  3. In HomeController:

    public class HomeController : Controller
    {
        private readonly ITestService _service;
        public HomeController(ITestService service)
        {
            _service = service;
        }
    
        public ActionResult Index()
        {
            ViewBag.Message = _service.GetMessage();
            return View();
        }
    }
    
  4. In App_Start/NinjectMVC3.cs:

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ITestService>().To<TestService>();
    }       
    
Poorly answered 15/3, 2011 at 17:2 Comment(1)
Thank-you, seems pretty straight forward. Now what would a good practice be for keeping the kernel around? Use a singleton as a global store?Paresh
S
4

Add the ITestService as a constructor parameter to your controller:

private ITestService service;

public MyController(ITestService service)
{
   this.service = service;
}

public ActionResult Index()
{
  ViewBag.Message = this.service.GetMessage();
  return View();
}

Ninject will automatically inject the ITestService into your controller. Then use the service field inside your Index method.


Alternately, if you don't want Ninject to inject into your controller constructor, you can keep around the kernel you create, then inside your Index method, you call kernel.Get<ITestService>() to grab an instance:

public ActionResult Index()
{
  var kernel = ... // Go grab the kernel we created back in app startup.
  ITestService service = kernel.Get<ITestService>();

  ViewBag.Message = service.GetMessage();
  return View();
}

Have a look at Ninject dependency inject for controllers in MVC3.

Stringent answered 15/3, 2011 at 16:59 Comment(3)
Thank-you, that makes sense. Now what would a good practice be for keeping the kernel around? Use a singleton as a global store?Paresh
Personally, I have a static class called Dependency, with a single method: Get<T>. That internally calls the kernel's Get method. Consuming code then looks like: Dependency.Get<IFoo>()Stringent
I would consider using the [Inject] parameter on the property instead of either a reference to the kernel, or the parameter-in-constructor approach. Adding constructors to your controllers will make for more verbose code if you have an interface on a base class that has to be passed in to every inherited constructor. ninject.codeplex.com/wikipage?title=Injection%20PatternsTempered

© 2022 - 2024 — McMap. All rights reserved.