Make sure that the controller has a parameterless public constructor error

scarpacci picture scarpacci · Jun 17, 2014 · Viewed 195k times · Source

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.

Answer

Steven picture Steven · Jun 17, 2014

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()));