Search code examples
c#asp.net-web-apininject

Ninject Web Api "Make sure that the controller has a parameterless public constructor."


I've been using ninject for almost 2 years but now when using it my ASP.NET MVC/WebAPI project i get this message and the previous threads on stackoverflow with various suggestions hasn't solved my problem. I have the follow nuget packages: Ninject MVC3 Ninject Integration for WebApi 2.

I've tried solving the problem for longer that I'd like too and would really appreciate any help and suggestions that i could get! (Id gladly put the solution on Github if someone want to take a closer look)

Here are the classes that I use:

public class CmsContext : DbContext
{

    public CmsContext()
        : base("CMS_POC")
    { }

    public DbSet<Activity> Activities { get; set; }
    public DbSet<CMS.Entities.System> Systems { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    }
}

public interface IRepository<T> where T : IEntityBase
{
    IEnumerable<T> GetAll { get; }
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    T GetById(int Id);
}

public class SystemRepository : IRepository<CMS.Entities.System>
{
    private CmsContext _systemContext;

    public SystemRepository(CmsContext systemContext)
    {
        _systemContext = systemContext;
    }

    public IEnumerable<Entities.System> GetAll
    {
        get
        {
            return _systemContext.Systems;
        }
    }

    public void Add(Entities.System entity)
    {
        _systemContext.Systems.Add(entity);
        _systemContext.SaveChanges();
    }

    public void Delete(Entities.System entity)
    {
        _systemContext.Systems.Remove(entity);
        _systemContext.SaveChanges();
    }

    public void Update(Entities.System entity)
    {
        var system = _systemContext.Systems.SingleOrDefault(s => s.System_Id == entity.System_Id);

        system = entity;
        _systemContext.SaveChanges();
    }

    public Entities.System GetById(int Id)
    {
        return _systemContext.Systems.SingleOrDefault(s => s.System_Id == Id);

}

public class ActivityRepository : IRepository<Activity>
{
    private CmsContext _activityContext;

    public ActivityRepository(CmsContext activityContext)
    {
        _activityContext = activityContext;
    }


    public IEnumerable<Activity> GetAll
    {
        get
        {
            return _activityContext.Activities;
        }
    }

    public void Add(Activity entity)
    {

        _activityContext.Activities.Add(entity);
        _activityContext.SaveChanges();
    }

    public void Delete(Activity entity)
    {
        _activityContext.Activities.Remove(entity);
        _activityContext.SaveChanges();
    }

    public void Update(Activity entity)
    {
        var activity = _activityContext.Activities.SingleOrDefault(a => a.Activity_Id == entity.Activity_Id);

        activity = entity;
        _activityContext.SaveChanges();

    }

    public Activity GetById(int Id)
    {
        return _activityContext.Activities.SingleOrDefault(a => a.Activity_Id == Id);
    }


 }

public interface IActivityService
    {
        IReadOnlyList<Activity> GetActivities();
        Activity GetSingleActivity(int id);
        Activity CreateActivity(string activityName, DateTime startDate, DateTime endDate, int systemId);
        Activity UpdateActivity(int activityId, string activityName, DateTime startDate, DateTime endDate);
        void DeleteActivity(int activityId);
    }

public interface ISystemService
    {
        IReadOnlyList<CMS.Entities.System> GetSystems();
        CMS.Entities.System GetSingleSystem(int id);
        CMS.Entities.System CreateSystem(string systemName);
        CMS.Entities.System UpdateSystem(int systemId, string systemName);
        void DeleteSystem(int systemId);
    }

    public class ActivityService : IActivityService
    {
        private IRepository<Activity> _activityRepository;
        private IRepository<Entities.System> _systemRepository;

        public ActivityService(IRepository<Activity> activityRepository, IRepository<Entities.System> systemRepository)
        {
            _activityRepository = activityRepository;
            _systemRepository = systemRepository;
        }
}

This is just a short part of the service class but I want to show how I'm using DI with the services.

And finally there configuration for ninject:

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<IActivityService>().To<ActivityService>();
        kernel.Bind<ISystemService>().To<SystemService>();
        kernel.Bind<IRepository<Activity>>().To<ActivityRepository>();
        kernel.Bind<IRepository<CMS.Entities.System>>().To<SystemRepository>();
    }        
}

EDIT* Forgot my controller

public class ActivitiesController : ApiController

{
    private IActivityService _activityService;

    public ActivitiesController(IActivityService activityService)
    {
        _activityService = activityService;
    }
}

Solution

  • So I've never really used ninject but I've spent a lot of time working with structuremap in WebApi (and have even gone through the effort of writing about how WebApi creates controllers) and I'm pretty sure I know whats going on.

    It looks like you've never registered your Kernel with WebApi. WebApi creates controllers via a IControllerActivator (which you can replace, but probably don't want to since it does a lot of caching and stuff for you) which in turn calls a DependencyResolver to create your controller. If you haven't registered your own resolver it will just use Activator.CreateInstance() which throws the error you're seeing.

    You'll need to either use an IDependencyResolver from a library (such as this one) or implement your own IDependencyResolver and IDependencyScope (a StructureMap example can be found here). Once you have an implementation you can register it with web API like this:

    GlobalConfiguration.Configuration.DependencyResolver = myResolverImpl;
    

    If you have any questions about this or this doesn't work please ask, this is an area where I'm trying to make sure I understand things well so I'd love to fill any holes in my knowledge.