Make sure that the controller has a parameterless public constructor error
Asked Answered
D

11

131

I have followed this tutorial which has worked great, until I modified my DbContext to have an additional constructor. I am now having issues with the resolution and not sure what to do to fix this. Is there an easy way to force it to grab the parameterless constructor or I am approaching this incorrectly?

DbContext with two constructors:

public class DashboardDbContext : DbContext
{
    public DashboardDbContext() : base("DefaultConnection") { }

    public DashboardDbContext(DbConnection dbConnection, bool owns)
        : base(dbConnection, owns) { }
}

SiteController constructor:

private readonly IDashboardRepository _repo;

public SiteController(IDashboardRepository repo)
{
    _repo = repo;
}

Repository:

DashboardDbContext _context;

public DashboardRepository(DashboardDbContext context)
{
    _context = context;
}

UnityResolver code:

public class UnityResolver : IDependencyResolver
{
    private readonly IUnityContainer _container;

    public UnityResolver(IUnityContainer container)
    {
        _container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return _container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return _container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = _container.CreateChildContainer();
        return new UnityResolver(child);
    }

    public void Dispose()
    {
        _container.Dispose();
    }
}

WebApiConfig:

var container = new UnityContainer();
container.RegisterType<IDashboardRepository, DashboardRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);

Error from WebApi Call:

System.InvalidOperationException: An error occurred when trying to create a controller of type 'SiteController'. Make sure that the controller has a parameterless public constructor.

at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) 
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request) 
at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) 
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()

InnerException: System.ArgumentException: Type 'Dashboard.Web.Controllers.SiteController' does not have a default constructor.

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)

The tutorial was great and has been working well for me up until I added the second constructor.

Dodd answered 17/6, 2014 at 0:41 Comment(13)
The error is telling you that SiteController is what must have a paramertless constructor, not DashboardDbContext.Retain
Hi Smith.h.Neil, but it only throws that error when the additional constructor is added to the dbcontext. If I remove that or comment it out (second constructor) it works fine.Dodd
Can I see the constructor for SiteController?Retain
And I'm guessing you're injecting the DbContext into the repository?Retain
@Dodd Are you sure the only change you're making is removing the second constructor from the DbContext? Unless you're somehow bypassing instantiation of your controller by not having the second DbContext constructor, it would make no sense for the error to be dependent on the DbContext's constructors.Taste
@Asad yep I am sure. I comment out the second constructor in the db context above and it works fine. It has something to do with the resolver grabbing the wrong constructor (my guess), but I am not sure how to limit it to the default.Dodd
@Dodd Could you show us your repository implementation? Does it explicitly new up a DbContext or have it injected?Taste
Hi @Asad, I updated with the info from repository...it is injectedDodd
Where is the unity code \ config?Personalize
assuming that you are using DI pattern, can I ask you specify the mapping here? nInject / Unity code?Croup
I updated the info to show the unity code / resolverDodd
Where are you registering your services? Your controller's constructor accepts something that implements IDashboardRepository, but where did you tell Unity to map IDashboardRepository to anything?Fustanella
@Fustanella in the webapiconfig (added to examples above).Dodd
B
145

What's happening is that you're bitten by this problem. Basically, what happened is that you didn't register your controllers explicitly in your container. Unity tries to resolve unregistered concrete types for you, but because it can't resolve it (caused by an error in your configuration), it return null. It is forced to return null, because Web API forces it to do so due to the IDependencyResolver contract. Since Unity returns null, Web API will try to create the controller itself, but since it doesn't have a default constructor it will throw the "Make sure that the controller has a parameterless public constructor" exception. This exception message is misleading and doesn't explain the real cause.

You would have seen a much clearer exception message if you registered your controllers explicitly, and that's why you should always register all root types explicitly.

But of course, the configuration error comes from you adding the second constructor to your DbContext. Unity always tries to pick the constructor with the most arguments, but it has no idea how to resolve this particular constructor.

So the real cause is that you are trying to use Unity's auto-wiring capabilities to create the DbContext. DbContext is a special type that shouldn't be auto-wired. It is a framework type and you should therefore fallback to registering it using a factory delegate:

container.Register<DashboardDbContext>(
    new InjectionFactory(c => new DashboardDbContext())); 
Bacillus answered 17/6, 2014 at 6:31 Comment(3)
PLEASE NOTE when you rebuild your project you may reset your login credentials... before trying to apply this solution please: re-build your project, log yourself out, then in again, only then - refresh your page and observe if the problem persistMontelongo
Thank you - these dingleberries on my backend team break a lot of rules with the unity configs. Starting to wonder if that's how every team uses IOC containers.Sclerotic
@Dagrooms: Many developers are bit by this, but this is not a problem that exists in all DI Containers. Simple Injector for instance, will always ensure that an expressive error is prompted in case such thing happens. Another good tip: Don't use a custom IDependencyResolver but only use a custom IControllerActivator instead.Bacillus
C
59

In my case, it was because of exception inside the constructor of my injected dependency (in your example - inside DashboardRepository constructor). The exception was caught somewhere inside MVC infrastructure. I found this after I added logs in relevant places.

Complementary answered 13/1, 2015 at 6:51 Comment(5)
This is a really important answer. It's very easy to fall into the trap of chasing set-up issues with Unity when seeing Make sure that the controller has a parameterless public constructor. but it's quite possible the dependency is set-up but an exception deep in the bowels has stopped it being resolved.Sabin
This. A million times! I forgot to add a dependency map to my Ninject configuration.Extracellular
My deep in the bowels exception was a property type of 'string' when it should have been 'DateTime?'. Would not have looked for that had I not seen this answer. Thanks so very much.Doublefaced
More like LousyErrorMessageException()Yolanda
What relevant places did you place the log? I ran from debugger but got no exception, even when I checked all CLR exceptions. I had to add manual constructor resolve and only then I got the error. It told me to add Diagnostic to get a usable error, that finally gave me something to work withTamalatamale
A
8

I had the same issue and I resolved it by making changes in the UnityConfig.cs file In order to resolve the dependency issue in the UnityConfig.cs file you have to add:

public static void RegisterComponents()    
{
    var container = new UnityContainer();
    container.RegisterType<ITestService, TestService>();
    DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
Aday answered 25/6, 2016 at 9:39 Comment(0)
W
6

I had the same problem. I googled it for two days. At last I accidentally noticed that the problem was access modifier of the constructor of the Controller. I didn’t put the public key word behind the Controller’s constructor.

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

        public MyController(IMyClass myClass)
        {
            _myClass = myClass;
        }
    }

I add this experience as another answer maybe someone else made a similar mistake.

Wasson answered 5/5, 2018 at 10:34 Comment(1)
make sure to also check the access modifiers for any injected dependencies. you'll get this error if they aren't public as wellCubbyhole
D
5

Sometimes because you are resolving your interface in ContainerBootstraper.cs it's very difficult to catch the error. In my case there was an error in resolving the implementation of the interface I've injected to the api controller. I couldn't find the error because I have resolve the interface in my bootstraperContainer like this: container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
then I've adde the following line in my bootstrap container : container.RegisterType<MyController>(); so when I compile the project , compiler complained and stopped in above line and showed the error.

Dramamine answered 3/6, 2016 at 4:59 Comment(0)
B
3

If you are using UnityConfig.cs to resister your type's mappings like below.

public static void RegisterTypes(IUnityContainer container)
    {
     container.RegisterType<IProductRepository, ProductRepository>();
    }

You have to let the know **webApiConfig.cs** about Container

config.DependencyResolver = new Unity.AspNet.WebApi.UnityDependencyResolver(UnityConfig.Container);
Bullfrog answered 23/6, 2019 at 16:12 Comment(0)
O
1

In my case, Unity turned out to be a red herring. My problem was a result of different projects targeting different versions of .NET. Unity was set up right and everything was registered with the container correctly. Everything compiled fine. But the type was in a class library, and the class library was set to target .NET Framework 4.0. The WebApi project using Unity was set to target .NET Framework 4.5. Changing the class library to also target 4.5 fixed the problem for me.

I discovered this by commenting out the DI constructor and adding default constructor. I commented out the controller methods and had them throw NotImplementedException. I confirmed that I could reach the controller, and seeing my NotImplementedException told me it was instantiating the controller fine. Next, in the default constructor, I manually instantiated the dependency chain instead of relying on Unity. It still compiled, but when I ran it the error message came back. This confirmed for me that I still got the error even when Unity was out of the picture. Finally, I started at the bottom of the chain and worked my way up, commenting out one line at a time and retesting until I no longer got the error message. This pointed me in the direction of the offending class, and from there I figured out that it was isolated to a single assembly.

Ozoniferous answered 24/9, 2019 at 20:11 Comment(0)
R
1

I really, really hope this answer helps someone else from wasting a day and a half of messing around with; Ninject, MVC design pattern, Global.asax, Web Common files etc etc.

The error itself was completely misleading in my case.

My entire application was working sound with the exception of when I called one particualr controller lets call TestController.

Test controller was using Ninject to inject an interface lets call ITest like so -

public class TestController : ApiController
{
    private readonly ITest _test;

    public TestController (ITest test)
    {
        _test= test;
    }

I was making a simple GET request to one of the methods in TestController and was getting the aforementioned error for this threads question.

I eventually boiled it down to the error only occuring when ITest was injected as a parameter (as I tested a different interface and it worked soundly!)

This led me to check the Test class and realsied that I had injected an instance of itself into it! Like so -

public class Test: ITest
{
    private readonly ITest_test;

    public Test(ITest test)
    {
        _test = test;
    }

Thus resulting in the entire call falling over as an unhandled exception and returning a completely bizarre error that didn't help me at all!

Revelatory answered 19/4, 2021 at 11:21 Comment(1)
This also happens if you mistakenly add the same interface twiceCascabel
A
0

If you have an interface in your controller

public myController(IXInterface Xinstance){}

You must register them to Dependency Injection container.

container.Bind<IXInterface>().To<XClass>().InRequestScope();
Apotropaic answered 17/10, 2018 at 8:37 Comment(0)
L
0

I've got this error when I accidentally defined a property as a specific object type, instead of the interface type I have defined in UnityContainer.

For example:

Defining UnityContainer:

var container = new UnityContainer();
container.RegisterInstance(typeof(IDashboardRepository), DashboardRepository);
config.DependencyResolver = new UnityResolver(container);

SiteController (the wrong way - notice repo type):

private readonly DashboardRepository _repo;

public SiteController(DashboardRepository repo)
{
    _repo = repo;
}

SiteController (the right way):

private readonly IDashboardRepository _repo;

public SiteController(IDashboardRepository repo)
{
    _repo = repo;
}
Lillie answered 29/11, 2018 at 8:40 Comment(0)
H
0

Install Nuget Package Unit.WebAP instead of Unity.MVC5 Make sure the correct unity package is installed using nuget

I Installed Unity.MVC5 and was facing similar exception "parameterless constructor"

 public static void RegisterComponents()
{
    var container = new UnityContainer();

    // register all your components with the container here
    // it is NOT necessary to register your controllers

    // e.g. container.RegisterType<ITestService, TestService>();
    container.RegisterType<ICar, Tesla>();
    GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
Hygrophilous answered 7/10, 2021 at 16:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.