Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ninject and ASP.NET Web API

Before I set up the question you should know that I got my current code from this page: http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/

I'm trying to use ASP.NET Web API and Ninject in my application by using an IDependencyResolver adapter found on the site above.

I created all the code just like it shows on the site and it works but when I load up my appication my regular controllers fail and show this error:

[MissingMethodException: No parameterless constructor defined for this object.]
[InvalidOperationException: An error occurred when trying to create a controller of type 'AccountManager.Controllers.HomeController'...

So, it seems like I can use Ninject with regular controllers or Web API controllers but not both. :(

Here is my code:

NinjectResolver.cs

public class NinjectResolver : NinjectScope, IDependencyResolver
{
    private IKernel _kernel;

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

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

NinjectScope.cs

public class NinjectScope : IDependencyScope
{
    protected IResolutionRoot resolutionRoot;

    public NinjectScope(IResolutionRoot kernel)
    {
        resolutionRoot = kernel;
    }

    public object GetService(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).SingleOrDefault();
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).ToList();
    }

    public void Dispose()
    {
        IDisposable disposable = (IDisposable)resolutionRoot;
        if (disposable != null) disposable.Dispose();
        resolutionRoot = null;
    }
}

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    private void SetupDependencyInjection()
    {
        //create Ninject DI Kernel
        IKernel kernel = new StandardKernel();

        //register services with Ninject DI container
        RegisterServices(kernel);

        //tell asp.net mvc to use our Ninject DI Container
        GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
    }
}

AccountingController.cs

public class AccountingController : ApiController
{
    private ICustomerService _customerService;

    public AccountingController(ICustomerService service)
    {
        _customerService = service;
    }

    // GET /api/<controller>/5
    public string Get(int id)
    {
        return "value";
    }
}
like image 818
Aaron Salazar Avatar asked Jul 25 '12 15:07

Aaron Salazar


People also ask

What is NInject Web API?

NInject is a popular IOC container that can be used to inject dependencies in your WebAPI controllers easily. IDG. Dependency injection is a software design pattern that helps you to build pluggable implementations in your application using loosely coupled, testable components.

Why NInject is used?

Ninject is a lightweight dependency injection framework for . NET applications. It helps you split your application into a collection of loosely-coupled, highly-cohesive pieces, and then glue them back together in a flexible manner.

What is the use of dependency injection in Web API?

When Web API creates a controller instance, it first calls IDependencyResolver. GetService, passing in the controller type. You can use this extensibility hook to create the controller, resolving any dependencies. If GetService returns null, Web API looks for a parameterless constructor on the controller class.


2 Answers

Insert the following line of code into the CreateKernel() method before the call to the RegisterServices(kernel); is made.

GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

You will also need to use the below code, I prefer to have it defined in the same class.

public class NinjectResolver : NinjectScope, IDependencyResolver
{
    private IKernel _kernel;
    public NinjectResolver(IKernel kernel)  : base(kernel)
    {
        _kernel = kernel;
    }
    public IDependencyScope BeginScope()
    {
        return new NinjectScope(_kernel.BeginBlock());
    }
}

public class NinjectScope : IDependencyScope
{
    protected IResolutionRoot resolutionRoot;
    public NinjectScope(IResolutionRoot kernel)
    {
        resolutionRoot = kernel;
    }
    public object GetService(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).SingleOrDefault();
    }
    public IEnumerable<object> GetServices(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).ToList();
    }
    public void Dispose()
    {
        IDisposable disposable = (IDisposable)resolutionRoot;
        if (disposable != null) disposable.Dispose();
        resolutionRoot = null;
    }
}

Run it, and it should work. This worked for me, I hope it does for you too.

Further Reading :

Using Ninject – Dependency Injection with ASP.NET Web API controllers

like image 71
Yasser Shaikh Avatar answered Oct 24 '22 04:10

Yasser Shaikh


I have a Web API project working using exactly the same solution as you from strathweb, so I just added a normal controller to the project, and it does work. Not a great help on it's own for you, so I'll detail the setup I've got:

I have the following packages installed (on the IOC side of things):

  • Ninject 3.0.1.10
  • Ninject MVC 3.0.0.6
  • Ninject.Web.Common 3.0.0.7
  • WebActivator 1.5.1

I have absolutely nothing in my Global.asax.cs file regarding Ninject, instead using the NinjectWebCommon.cs file that is automatically created in App_Start when you install Ninject. I don't know if by having code in your Global file that means that Ninject hasn't set itself up correctly in your project?

Here is the code in NinjectWebCommon.cs:

    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();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);

        GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

        return kernel;
    }

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

Here's the other difference I can see between our code, where I create the Kernel, my code declares two bindings to the kernel.

Here's the code for my test controller, I can set a breakpoint in the constructor and it gets it:

public class TestController : Controller
{
    IUserManager _userManager;

    public TestController(IUserManager userManager)
    {
        _userManager = userManager;
    }

    //
    // GET: /Test/
    public ActionResult Index()
    {
        return View();
    }
}

This works with both my Controller and my APIControllers.

like image 23
Paul Manzotti Avatar answered Oct 24 '22 06:10

Paul Manzotti