24
votes

I have the following packages and their dependencies installed in my WebAPI project:

Ninject.Web.WebApi Ninject.Web.WebApi.OwinHost

I am running this purely as a web-api project. No MVC.

When I run my application and send a POST to the AccountController's Register action I get the following error returned:

{
"message":"An error has occurred.",
"exceptionMessage":"An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor.",
"exceptionType":"System.InvalidOperationException",
"stackTrace":"   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()",
"innerException":{
"message":"An error has occurred.",
"exceptionMessage":"Type 'RPT.Api.Controllers.AccountController' does not have a default constructor",
"exceptionType":"System.ArgumentException",
"stackTrace":"   at System.Linq.Expressions.Expression.New(Type type)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}

Can anyone help me as the only details I can find on Google seem to be from 2012.

Note: I've also tried AutoFac instead of Ninject and get the same error there too. Most frustrating.

Here's my NinjectWebCommon.cs:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using RPT.Data;
using RPT.Services;
using RPT.Services.Interfaces;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(RPT.Api.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(RPT.Api.NinjectWebCommon), "Stop")]

namespace RPT.Api
{
    using System;
    using System.Web;

    using Microsoft.Web.Infrastructure.DynamicModuleHelper;

    using Ninject;
    using Ninject.Web.Common;

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

                RegisterServices(kernel);


                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<RptContext>().ToSelf();

            kernel.Bind<IUserStore<IdentityUser>>().To<UserStore<IdentityUser>>();
            kernel.Bind<UserManager<IdentityUser>>().ToSelf();

            kernel.Bind<IAccountService>().To<AccountService>();
        }
    }
}

Here's my AccountController:

using System.Threading.Tasks;
using System.Web.Http;
using System.Web.ModelBinding;
using Microsoft.AspNet.Identity;
using RPT.Api.Models;
using RPT.Services.Interfaces;

namespace RPT.Api.Controllers
{
    [RoutePrefix("api/account")]
    public class AccountController : ApiController
    {
        #region Initialisation

        private readonly IAccountService _accountService;

        public AccountController(IAccountService accountService) : base()
        {
            _accountService = accountService;
        }

        #endregion

        #region Actions

        [AllowAnonymous]
        [Route("register")]
        public async Task<IHttpActionResult> Register(UserRegistrationViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var result = await _accountService.RegisterUser(model.UserName, model.Password);

            var errorResult = GetErrorResult(result);

            return errorResult ?? Ok();
        }

        #endregion

        #region Internal

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _accountService.Dispose();
            }

            base.Dispose(disposing);
        }
        private IHttpActionResult GetErrorResult(IdentityResult result)
        {
            if (result == null)
            {
                return InternalServerError();
            }

            if (result.Succeeded) return null;
            if (result.Errors != null)
            {
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError("", error);
                }
            }

            if (ModelState.IsValid)
            {
                // No ModelState errors are available to send, so just return an empty BadRequest.
                return BadRequest();
            }

            return BadRequest(ModelState);
        }

        #endregion
    }
}
10
Not sure about doing IoC using WebActivatorEx, but there's an example on the web-api site that registers containers using IDependencyResolver. Perhaps you could modify your code to implement this interface instead? asp.net/web-api/overview/extensibility/…failedprogramming
@failedprogramming Doesn't the Ninject.WebApi package include a dependency resolver in the same way that the Ninject.MVC3 package does for MVC applications?Hades
Old thread but posting in case someone has the same issue. For me this was because I'd done kernel.Bind<IDep, ConcreteDep>() rather than kernel.Bind<IDep>().To<ConcreteDep>();Dillanm

10 Answers

20
votes

Did you modify your OWIN Startup class to call app.UseNinjectWebApi and app.UseNinjectMiddleware rather than calling app.UseWebApi?

Startup.cs in the Ninject Web API samples does this...

15
votes

In my case, the reason was resolver could not find a mapping. That is suppose say HomeController has a dependency on IDumb, the resolver could not find a concrete implementation of Dumb with implements IDumb. In other words the error message

**No parameterless constructor defined for this object
An error occurred when trying to create a controller of type 'ToDoListT1.WebApp.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor**

is completely misleading. In my case I just resolved by adding a reference to the project of the class Dumb. It should have been something like "No mapping for IDumb could be found.". I am not sure the problem is with NInject or MS. What ever it took me hours to find this out.

4
votes

My solution is add "public" keyword to constructor.

4
votes

What worked for me was adding the NuGet package Ninject.Web.WebApi.WebHost as described here: https://github.com/ninject/Ninject.Web.WebApi/wiki/Setting-up-an-mvc-webapi-application

2
votes

Make sure you have registered all the types used by the controller, all the way down to the database.

In my case, I had only added the interface that the controller itself used, but not the interface used to actually query the database.

Notice in the code below how the AddUserMaintenanceProcessor class has dependencies that the controller does not know about. If you omit the Unity (or whatever IoC tool you use) type mappings for these dependencies, the controller construction will fail.

My solution uses Unity, but the point I'm trying to make is that you need to create type mappings for all dependencies.

Startup.cs

public void Configuration(IAppBuilder app)
{
    var config = new HttpConfiguration();

    // Configure Unity
    var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
    GlobalConfiguration.Configuration.DependencyResolver = resolver;
    config.DependencyResolver = resolver;

    // Do Web API configuration
    WebApiConfig.Register(config);

    app.UseWebApi(config);
}

UnityConfig.cs

public class UnityConfig
{
    private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    // Gets the configured Unity container
    public static IUnityContainer GetConfiguredContainer()
    {
        return Container.Value;
    }

    // Register type mappings
    public static void RegisterTypes(IUnityContainer container)
    {
        // LogManagerAdapter wrapping e.g. log4net
        container.RegisterType<ILogManager, LogManagerAdapter>();

        // AutoMapperAdapter wrapping e.g. AutoMapper (configuration omitted)
        container.RegisterType<IAutoMapper, AutoMapperAdapter>();

        // Interface for persisting the user
        container.RegisterType<IAddUserQueryProcessor, AddUserQueryProcessor>();

        // Interface for doing application logic in regards to adding a user
        container.RegisterType<IAddUserMaintenanceProcessor, AddUserMaintenanceProcessor>();
    }
}

UsersController.cs

public class UsersController : ApiController
{
    private readonly IAddUserMaintenanceProcessor _addUserProcessor;

    public UsersV1Controller(IAddUserMaintenanceProcessor addUserProcessor)
    {
        _addUserProcessor = addUserProcessor;
    }

    public async Task<UserModel> Post(NewUser user)
    {
        return await _addUserProcessor.AddUserAsync(user);
    }

    // ...
}

AddUserMaintenanceProcessor.cs

public class AddUserMaintenanceProcessor : IAddUserMaintenanceProcessor
{
    private readonly IAddUserQueryProcessor _queryProcessor;
    private readonly ILog _logger;
    private readonly IAutoMapper _mapper;

    public AddUserMaintenanceProcessor(
        IAddUserQueryProcessor queryProcessor,
        ILogManager logManager,
        IAutoMapper mapper)
    {
        _queryProcessor = queryProcessor;
        _logger = logManager.GetLog(typeof(AddUserMaintenanceProcessor));
        _mapper = mapper;
    }

    public async Task<UserModel> AddUserAsync(NewUser newUser)
    {
        _logger.Info($"Adding new user {newUser.UserName}");

        // Map the NewUser object to a User object
        var user = _mapper.Map<User>(newUser);

        // Persist the user to a medium unknown to this class, using the query processor,
        // which in turn returns a User object
        var addedUser = await _queryProcessor.AddUserAsync(user);

        // Map the User object back to UserModel to return to requester
        var userModel = _mapper.Map<UserModel>(addedUser);

        _logger.Info($"User {userModel.UserName} added successfully");

        return userModel;
    }
}

I have omitted the interfaces for the processors as they only contain one method (Strategy pattern). The interfaces for logging and auto mapping are irrelevant to this question.

The AddUserQueryProcessor class simply persists the user to the database. Once again irrelevant to this question.

1
votes

This applies to older versions of Ninject, or if you are not using the auto-generated bootstrap code from Ninject.Web.WebApi.Webhost.

You are missing a dependency resolver, its a really basic implementation:

public class NinjectHttpDependencyResolver : IDependencyResolver, IDependencyScope
{
    private readonly IKernel _kernel;
    public NinjectHttpDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }
    public IDependencyScope BeginScope()
    {
        return this;
    }

    public void Dispose()
    {
        //Do nothing
    }

    public object GetService(Type serviceType)
    {
        return _kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _kernel.GetAll(serviceType);
    }
}

Then just register it when you create the kernel:

var httpResolver = new NinjectHttpDependencyResolver(kernel);
GlobalConfiguration.Configuration.DependencyResolver = httpResolver;
0
votes

For me, what caused this error was that for the interface I was passing into the constructor, I had a named binding and I called it with the wrong name. As you can see the below, the binding says it's named "Warehouse", but I got things mixed up and put "DataWarehouse" in the constructor. Getting this straightened out caused the error about a parameterless constructor to go away.

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IVisitProcessor>().To<VisitProcessor>().InThreadScope();
        kernel.Bind<IPatientProcessor>().To<PatientProcessor>().InThreadScope();
        kernel.Bind<IDbConnectionFactory>().To<SqlConnectionFactory>().Named("Warehouse").WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["DataWarehouse"].ConnectionString);
    }

constructor:

//WRONG NAME
public VisitProcessor([Named("DataWarehouse")] IDbConnectionFactory connection)
    {
        _database = connection;
    }
0
votes

I too was trying to make an 'only API' app, but faced similar issues. For me personally, in the end it came down the selecting the right starting template.

Despite going for API-only, when in the 'Create a new ASP.NET Web Application" wizard, selecting the 'Empty' application-type and choosing MVC and Web API in the 'add folders & core references' section made Ninject work fine:

enter image description here

As opposed to the 'Web API' application, which didn't play nice with Ninject:

enter image description here

After that, it's simply to add the Ninject.Web.WebApi.WebHost package, which adds the NinjectWebCommon.cs class, and start adding dependencies.

enter image description here

0
votes

I've got a situation where I have a service, and into it injected other services. One of these injected services had another injected services, and one of them was not registered properly for dependency injection.

I set a breakpoint in the constructor of services that were injected in controller (services before one that was causing a problem). In debugging it was shown for which service it cannot resolve the dependency.

0
votes

As other answers have pointed out, the error message can be misleading. Ninject might be working fine, but it could be that some dependency cannot be instantiated for a variety of reasons, such as:

  • A missing binding for an indirect dependency: https://stackoverflow.com/a/36438210/2279059
  • A dependency does not have a default constructor and does not support dependency injection (e.g., missing [Inject] property).
  • A cyclical dependency between two services

You do not see all details in the error returned by the server (which may be by design). If you attach the debugger, you may also not be able to catch the exception unless you disable "Just My Code" in the debugging settings. Then you may be able to catch an internal Ninject exception which may have all the information you need to understand the problem.

Older versions of Ninject, or if you are not using Ninject.Web.WebApi.WebHost, also require that you register Ninject as a dependency resolver, as pointed out in https://stackoverflow.com/a/24196092/2279059.