11

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";
    }
}
2
  • Not used Ninject before, but is there a reason you can't add a parameterless constructor on the type Ninject is trying to inject into? Commented Jul 25, 2012 at 15:10
  • 4
    @Charleh: That would defeat the purpose of an IoC container. Commented Jul 25, 2012 at 15:11

2 Answers 2

17

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

Sign up to request clarification or add additional context in comments.

1 Comment

Just like many "works for me" tutorials for Ninject, this one is outdated.
3

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.