MVC 4 Web Api Controller does not have a default constructor?
Asked Answered
H

10

19

Here is the trace:

<Error>
   <Message>An error has occurred.</Message>

   <ExceptionMessage>
      Type 'ProjectName.Web.Api.Controllers.ContinentsController' does not have a default constructor
   </ExceptionMessage>

   <ExceptionType>System.ArgumentException</ExceptionType>

   <StackTrace>
      at System.Linq.Expressions.Expression.New(Type type)

      at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)

      at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)

      at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
   </StackTrace>
</Error>

I find this weird as public class UsersController : ApiController { ... } is working just fine. I have compared the 2 controllers, all the settings and structures are similar.

I am using Ninject and i have my system setup similar to Jamie Kurtz Asp.Net Mvc 4 and the Web Api: Building a REST Service from Start to Finish.

From the stack trace, is anyone able to spot the problem and how to solve it? Thanks!

As Requested.

ContinentsController

[LoggingNHibernateSession]
public class ContinentsController : ApiController
{
    private readonly ISession _session;
    private readonly IContinentMapper _continentMapper;
    private readonly IHttpContinentFetcher _httpContinentFetcher;
    private readonly IDateTime _dateTime;

    public ContinentsController(ISession session, IContinentMapper continentMapper, IHttpContinentFetcher continentFetcher, IDateTime dateTime)
    {
        _session = session;
        _continentMapper = continentMapper;
        _httpContinentFetcher = continentFetcher;
        _dateTime = dateTime;
    }

    public IEnumerable<Continent> Get()
    {
        var continents = _session
            .Query<Data.Model.Continent>()
            .Select(_continentMapper.CreateContinent)
            .ToList();

        return continents;
    }

    public Continent Get(long id)
    {
        var modelContinent = _httpContinentFetcher.GetContinent(id);
        var continent = _continentMapper.CreateContinent(modelContinent);

            return continent;
        }
  }

UsersController: Works just fine.

    public class UsersController : ApiController
    {
        private readonly ISession _session;
        private readonly IUserManager _userManager;
        private readonly IUserMapper _userMapper;
        private readonly IHttpUserFetcher _userFetcher;

        public UsersController(
            IUserManager userManager,
            IUserMapper userMapper,
            IHttpUserFetcher userFetcher,
            ISession session)
        {
            _userManager = userManager;
            _userMapper = userMapper;
            _userFetcher = userFetcher;
            _session = session;
        }

        [Queryable]
        public IQueryable<Data.Model.User> Get()
        {
            return _session.Query<Data.Model.User>();
        }

        [LoggingNHibernateSession]
        public User Get(Guid id)
        {
            var user = _userFetcher.GetUser(id);
            return _userMapper.CreateUser(user);
        }
    }

I am using NinjectWebCommon.cs and in it, i have this and a few other default methods.:

        private static void RegisterServices(IKernel kernel)
        {
            var containerConfigurator = new NinjectConfigurator();
            containerConfigurator.Configure(kernel);

            GlobalConfiguration.Configuration.MessageHandlers.Add(kernel.Get<BasicAuthenticationMessageHandler>());
        }

Then i have NinjectConfigurator.cs:

public class NinjectConfigurator
{
    ......
    private void AddBindings(IKernel container)
        {
            .....
            container.Bind<IDateTime>().To<DateTimeAdapter>();
            container.Bind<IDatabaseValueParser>().To<DatabaseValueParser>();

            //HttpFetchers
            container.Bind<IHttpUserFetcher>().To<HttpUserFetcher>();
            container.Bind<IHttpContinentFetcher>().To<HttpContinentFetcher>();                                

            //TypeMappers
            container.Bind<IUserManager>().To<UserManager>();
            container.Bind<IMembershipInfoProvider>().To<MembershipAdapter>();
            container.Bind<IUserMapper>().To<UserMapper>();
            container.Bind<IContinentMapper>().To<ContinentMapper>();    
            .........
        }
     .......
}

Both NinjectWebCommon.cs and NinjectConfigurator.cs are located in the App_Start folder.

container.Bind<ISession>().ToMethod(CreateSession); is NHibernate. It is within NinjectConfigurator.cs inside private void ConfigureNHibernate(IKernel container) { ... }

Herbarium answered 4/7, 2013 at 5:0 Comment(7)
The stacktrace is not enough to find out what is your problem, so please post the code of your ContinentsController!Tutelage
You have copied the code of the ContinentsController twice... but whatever. The problem is that one of the your contructor dependencies ISession session, IContinentMapper continentMapper, IHttpContinentFetcher continentFetcher, IDateTime dateTime is not registered in Ninject. Make sure that everything is registered or post your kernel bindings to lets us what is missing. And your UserController works fine because it has a completely different set of dependencies.Tutelage
@Tutelage I added what you requested.Herbarium
One more thing you can check: make sure that also all the constructor paramters of the HttpContinentFetcher and ContinentMapper also have been registered in the contianer...Tutelage
@Tutelage HttpContinentFetcher has ISession and ContinentMapper would take in child object's Mappers. ISession is already registered, and if i had a child of Continents i.e country, it would be registered.Herbarium
Did you set the Dependency Resolver on start up of your application?Halter
@FelipeOriani I have Dependency Resolver, and UserController works just fine.Herbarium
H
16

This error is a known error when you do not set the dependency resolver in your application. The Controller Factory could not find a parameterless constructor to create the controller and execute the action method (or verb method?). So, you have to create a dependency resolver class and set it on the initialization of your web app. It will resolve dependencies of your controllers.

Using ninject, you could try something like this:

using Ninject; 
using Ninject.Syntax; 
using System; 
using System.Collections.Generic; 
using System.Diagnostics.Contracts; 
using System.Web.Http.Dependencies; 

namespace MyApplication.App_Start 
{     
    public class NinjectDependencyScope : IDependencyScope     
    {         
        private IResolutionRoot resolver;         

        internal NinjectDependencyScope(IResolutionRoot resolver)         
        {             
            Contract.Assert(resolver != null);             
            this.resolver = resolver;         
        }         

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

        public object GetService(Type serviceType)         
        {             
            if (resolver == null)                 
                throw new ObjectDisposedException("this", "This scope has already been disposed");             

            return resolver.TryGet(serviceType);         
        }   

        public IEnumerable GetServices(Type serviceType)         
        {             
            if (resolver == null)                 
                throw new ObjectDisposedException("this", "This scope has already been disposed");             

            return resolver.GetAll(serviceType);         
        }     
    }     

    public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver     
    {         
        private IKernel kernel;         
        public NinjectDependencyResolver(IKernel kernel)             
            : base(kernel)         
        {             
            this.kernel = kernel;         
        }         

        public IDependencyScope BeginScope()         
        {             
            return new NinjectDependencyScope(kernel.BeginBlock());         
        }     
    } 
}

The NinjectDependencyResolver class takes a Ninject StandardKernel object as a constructor argument and this reference is used whenever a dependency scope is pipelined. To make this all work, the NinjectDependencyResolver class is assigned to the application's global configuration:

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

    // register all your dependencies on the kernel container
    RegisterServices(kernel);

    // register the dependency resolver passing the kernel container
    GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

    return kernel;
}

On your Global.asax.cs file in the end of Application_Start event, call this CreateKernel method.

Halter answered 5/7, 2013 at 18:27 Comment(2)
I had to just add GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel); to my NinjectWebCommon, didn't have to call method in global.asax.cs. ThanksDonniedonnish
in the end of Application_Start event -> this is important! I am using Unity, not Ninject, but I was getting all kinds of exceptions as I was setting the Resolver too early. Moving it to the end of this handler fixed it. Thanks Felipe!Mcquoid
S
18

You need to tell Ninject how to correctly resolve Web API dependencies.

You can use Felipe Oriani's answer, but if you like there is a NuGet package called WebApiContrib.IoC.Ninject which will do this for you.

  1. In Visual Studio Go to: Tools > NuGet Package Manager > Manage NuGet Packages for Solution

  2. Install the WebApiContrib.IoC.Ninject package

  3. Edit: NinjectWebCommon.cs and update the CreateKernel() method to include: GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

    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);
    
            //Note: Add the line below:
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
    
            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }
    
Stickle answered 7/1, 2015 at 21:25 Comment(1)
hey man! thanks, this works perfect in my webApi application. MVC 5.Patrology
H
16

This error is a known error when you do not set the dependency resolver in your application. The Controller Factory could not find a parameterless constructor to create the controller and execute the action method (or verb method?). So, you have to create a dependency resolver class and set it on the initialization of your web app. It will resolve dependencies of your controllers.

Using ninject, you could try something like this:

using Ninject; 
using Ninject.Syntax; 
using System; 
using System.Collections.Generic; 
using System.Diagnostics.Contracts; 
using System.Web.Http.Dependencies; 

namespace MyApplication.App_Start 
{     
    public class NinjectDependencyScope : IDependencyScope     
    {         
        private IResolutionRoot resolver;         

        internal NinjectDependencyScope(IResolutionRoot resolver)         
        {             
            Contract.Assert(resolver != null);             
            this.resolver = resolver;         
        }         

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

        public object GetService(Type serviceType)         
        {             
            if (resolver == null)                 
                throw new ObjectDisposedException("this", "This scope has already been disposed");             

            return resolver.TryGet(serviceType);         
        }   

        public IEnumerable GetServices(Type serviceType)         
        {             
            if (resolver == null)                 
                throw new ObjectDisposedException("this", "This scope has already been disposed");             

            return resolver.GetAll(serviceType);         
        }     
    }     

    public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver     
    {         
        private IKernel kernel;         
        public NinjectDependencyResolver(IKernel kernel)             
            : base(kernel)         
        {             
            this.kernel = kernel;         
        }         

        public IDependencyScope BeginScope()         
        {             
            return new NinjectDependencyScope(kernel.BeginBlock());         
        }     
    } 
}

The NinjectDependencyResolver class takes a Ninject StandardKernel object as a constructor argument and this reference is used whenever a dependency scope is pipelined. To make this all work, the NinjectDependencyResolver class is assigned to the application's global configuration:

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

    // register all your dependencies on the kernel container
    RegisterServices(kernel);

    // register the dependency resolver passing the kernel container
    GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

    return kernel;
}

On your Global.asax.cs file in the end of Application_Start event, call this CreateKernel method.

Halter answered 5/7, 2013 at 18:27 Comment(2)
I had to just add GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel); to my NinjectWebCommon, didn't have to call method in global.asax.cs. ThanksDonniedonnish
in the end of Application_Start event -> this is important! I am using Unity, not Ninject, but I was getting all kinds of exceptions as I was setting the Resolver too early. Moving it to the end of this handler fixed it. Thanks Felipe!Mcquoid
I
5

For me, it was just a matter of adding the Ninject.Web.WebApi.Webhost NuGet package.

For my applications that use both MVC and WebApi2, I have the following packages for Ninject:

  • Ninject
  • Ninject.MVC5
  • Ninject.Web.Common
  • Ninject.Web.Common.WebHost
  • Ninject.Web.WebApi
  • Ninject.Web.WebApi.WebHost
Ignacioignacius answered 14/9, 2018 at 20:3 Comment(1)
Had to add the Ninject.Web.Common.WebHost and Ninject.Web.WebApi.WebHost packages after updating Ninject 3.2.x to 3.3.xHorseshoe
G
2

I also ran into this identical error but from another cause using Ninject. I actually had the dependency resolver and configuration correct. In fact the app was working well until I tried to resolve another new dependency. I had the registration set for it, so I could not figure out what was missing.

The issue was I accidentally resolved the Interface to the same Interface as opposed to resolving to the proper concrete type. So using an example from the OP I did the following which results in the identical error:

container.Bind<IUserManager>().To<IUserManager>();

Notice resolving to IUserManager which was an oversight but it does lead to the identical error from the OP. Obviously the fix is to resolve to the proper concrete type.

Gerhardine answered 16/9, 2014 at 22:7 Comment(0)
C
1

I had this problem, too, but it just turned out that one of my interfaces weren't actually implemented by any classes (I forgot to add it to the class declaration).

Caoutchouc answered 24/2, 2015 at 18:10 Comment(0)
J
1

The accepted answer is from 2014. Since tons of people had this issue, as of 2016 there's a recipe for it. This just adds to the accepted answer.

The way I do it is by installing packages Ninject.MVC3 and WebApiContrib.IoC.Ninject. A file called NinjectWebCommon gets added to your App_Start folder. You can then use the built-in NinjectResolver.

Just add this method:

private static void AddWebApiSupport(StandardKernel kernel)
{
  // Support WebAPI
  GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
  GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider), new NinjectWebApiFilterProvider(kernel));
}

and call it before calling RegisterServices.

Jesus answered 17/5, 2017 at 15:15 Comment(0)
A
0

This is a common problem occurs mainly when you work with Ninject Dependency injection Container. Please follow the steps to resolve this problem.  Make sure you have Installed the following packages.

Again go for this and Install this- enter image description here

Now check the the App_start folder.You will find the following thing(NinjectWebcommon.cs). enter image description here

Now double click and check the following line in CreateKernel() method like this

 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);
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }

And then Register your dependincy like this

 private static void RegisterServices(IKernel kernel)
    {

        kernel.Bind<IProductDetails>().To<ProductDetails>().InRequestScope();
    }      

I am sure this will make your solution work.

Aurelia answered 13/6, 2017 at 14:55 Comment(0)
E
0
private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<ICountingKsRepository>().To<CountingKsRepository>();

Make sure the To<> part is a concrete class not an interface, as that will create the same error also!

Essieessinger answered 11/2, 2018 at 20:50 Comment(0)
A
0

In case any SimpleInjector users end up in here...

For me, it was simply that I had forgotten to add SimpleInjectorInitializer.Initialize(); to my Application_Start() method.

I typically create a SimpleInjectorInitializer class in the App_Start folder these days, within which I do the container.Verify() and GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); calls; after I've called my GetInitializeContainer() method that's doing all the type registrations, etc.

Amalgamate answered 4/9, 2019 at 18:53 Comment(0)
B
0

It was happening with me when I did not mention the interface and class for dependency injection in the web.config file.

Becker answered 9/9, 2019 at 10:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.