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

后端 未结 10 2045
心在旅途
心在旅途 2020-12-31 00:39

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

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

相关标签:
10条回答
  • 2020-12-31 01:03

    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.

    0 讨论(0)
  • 2020-12-31 01:05

    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.

    0 讨论(0)
  • 2020-12-31 01:06

    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 讨论(0)
  • 2020-12-31 01:07

    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.

    0 讨论(0)
提交回复
热议问题