Ninject error in WebAPI 2.1 - Make sure that the controller has a parameterless public constructor
Asked Answered
M

10

26

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
    }
}
Mudskipper answered 12/6, 2014 at 22:57 Comment(3)
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/…Kenakenaf
@Kenakenaf Doesn't the Ninject.WebApi package include a dependency resolver in the same way that the Ninject.MVC3 package does for MVC applications?Mudskipper
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>();Trimorphism
I
21

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...

Islam answered 13/6, 2014 at 0:7 Comment(5)
That looks like it wouldn't use NinjectWebCommon.cs then. Is that correct? If so where do I do my bindings?Mudskipper
I'm not sure where NinjextWebCommon.cs came from - is it usually added to MVC projects? You can configure the kernel and its bindings in the CreateKernel method in Startup.csIslam
NinjectWebCommon.cs is added by one of the Ninject nuget packages. I think it was either Ninject.Web.WebApi.OwinHost or Ninject.Web.WebApi.WebHost... this could be where my confusion has sprouted from.Mudskipper
Well, this worked for me... seems that NinjectWebCommon.cs is just not required with WebAPI/OWIN setups. Thanks muchly :)Mudskipper
This solution worked for me !!! :) Error was observed when all the 3 configuration settings were in place i.e. UseWebApi(), UseNinjectWebApi() and UseNinjectMiddleware() in application start instance. But, removing UseWebApi() and using only other 2 settings resolved the issue. We were using Ninject IOC and OWIN in the application. Hope this information helps people facing similar issue :)Anlage
H
17

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.

Houstonhoustonia answered 4/11, 2014 at 10:57 Comment(4)
THIS was what really helped me. Try to resolve the dependency on your own. You'll see that it fails. It seems that Web API calls a constructor with only the dependencies it could resolve as parameters and skipping the others.Chapiter
Little old, but I just spent hours fixing that error in MVC + WebApi, switched to Autofac, got a glorious exception and an hour later, everything fixed and running.Sirkin
For future reference, take a look at inner exception - it shows where the problem isMistrial
I am getting the same error, But the strange part is that this error is not persisting. Anybody experienced the same?Waterworks
S
5

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

Supplement answered 5/5, 2020 at 12:7 Comment(0)
D
4

My solution is add "public" keyword to constructor.

Deon answered 29/7, 2015 at 6:9 Comment(1)
Vote up, it was my issue too.Ries
W
2

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;
Wheelwright answered 13/6, 2014 at 0:42 Comment(2)
Doesn't the addition of the Ninject.WebApi package negate the need for this?Mudskipper
where do you get the kernel?Chichihaerh
J
2

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.

Jocund answered 5/4, 2016 at 22:28 Comment(1)
can you expand in this answer a some, some sample of the registration or something to make this a more complete answer. thanks youEasing
A
0

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;
    }
Aperient answered 21/5, 2018 at 18:1 Comment(0)
R
0

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

Roomy answered 11/6, 2020 at 11:55 Comment(1)
This may be because the Web API template already has a DI container installed... Ninject may have been conflicting.Mudskipper
I
0

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.

Involutional answered 10/7, 2020 at 7:7 Comment(0)
R
0

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:

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://mcmap.net/q/455809/-ninject-error-in-webapi-2-1-make-sure-that-the-controller-has-a-parameterless-public-constructor.

Ramon answered 24/7, 2020 at 12:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.