0

When I run my WebAPI project from Visual Studio it runs perfectly. But when I publish to the file system and copy the files to my IIS folder and run it, it fails with the error: An error occurred when trying to create a controller of type 'DepartmentsController'. Make sure that the controller has a parameterless public constructor.

Some of the other answers on SO like this one: MVC5, Web API 2 and and Ninject say that you need to install Ninject.Web.WebApi.WebHost, which I've done.

All my bindings are set and everything is initialized in NinjectWebCommon. NinjectWebCommon.Start() is being called when I'm debugging locally. I don't know what calls it as I can't find a reference to NinjectWebCommon.Start() anywhere in the application. Why would this work in local debug but fail in IIS?

using System.Web.Http;
using MyApp.WebAPI.Infrastructure;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(MyApp.WebAPI.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(MyApp.WebAPI.App_Start.NinjectWebCommon), "Stop")]

namespace MyApp.WebAPI.App_Start {
    using System;
    using System.Web;

    using Microsoft.Web.Infrastructure.DynamicModuleHelper;

    using Ninject;
    using Ninject.Web.Common;

    public static class NinjectWebCommon {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        public static void Start() {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            IKernel container = null;

            bootstrapper.Initialize(() => {
                container = CreateKernel();
                return container;
            });

            NinjectDependencyResolver resolver = new NinjectDependencyResolver(container);
            GlobalConfiguration.Configuration.DependencyResolver = resolver;
        }

        public static void Stop() {
            bootstrapper.ShutDown();
        }

        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;
            }
        }

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

This is where my bindings are:

using MyApp.DataAccess.Entities;
using MyApp.Domain.Abstract;
using MyApp.DataAccess.Repositories.Concrete;
using Ninject;
using Ninject.Web.Common;

namespace MyApp.WebAPI.App_Start {
    public class NinjectConfigurator {
        public void Configure(IKernel container) {
            AddBindings(container);
        }

        private void AddBindings(IKernel container) {
            container.Bind<MyAppContext>().ToSelf().InRequestScope();
            container.Bind<IUnitOfWork<MyAppContext>>().To<UnitOfWork<MyAppContext>>();
            container.Bind<IUserRepository>().To<UserRepository>();
            container.Bind<ITeamRepository>().To<TeamRepository>();
            container.Bind<IDepartmentRepository>().To<DepartmentRepository>();
            container.Bind<IDivisionRepository>().To<DivisionRepository>();
        }
    }
}

Here's the controller:

using System;
using System.Collections.Generic;
using System.Web.Http;
using MyApp.DataAccess.Entities;
using MyApp.Domain.Abstract;
using Department = MyApp.Domain.Models.Department;

namespace MyApp.WebAPI.Controllers
{
    public class DepartmentsController : ApiController {
        private IUnitOfWork<MyAppContext> _unitOfWork;

        public DepartmentsController(IUnitOfWork<MyAppContext> unitOfWork) {
            _unitOfWork = unitOfWork;
        }

        [HttpGet]
        public IHttpActionResult Get() {
            IEnumerable<Department> deptsList = _unitOfWork.Departments.GetAll();
            return Ok(deptsList);
        }

        [HttpGet]
        public IHttpActionResult Get(int id) {
            Department dept = _unitOfWork.Departments.Get(id);
            return Ok(dept);
        }

        [HttpGet]
        [Route("api/departments/division/{divisionId:int}")]
        public IHttpActionResult GetDepartmentsByDivision(int divisionId) {
            IEnumerable<Department> departmentsInDivision = _unitOfWork.Departments.GetDepartmentsByDivisionId(divisionId);
            return Ok(departmentsInDivision);
        }

        [HttpPost]
        public IHttpActionResult Post(Department department) {
            _unitOfWork.Departments.Add(department);

            //Make sure departmentId is updated from DB before passing back
            return Created("api/departments/" + department.DepartmentId, department);
        }

        [HttpPut]
        public IHttpActionResult Put(Department department) {
            _unitOfWork.Departments.Update(department);
            return Ok(department);
        }
    }
}
Legion
  • 3,922
  • 8
  • 51
  • 95

1 Answers1

0

Everything started working when I used NuGet to install EntityFramework to my WebAPI project. This makes no sense and completely defeats the purpose DI/Ninject and my data access layer, but I'll take a working bad design over a "good design" that doesn't work.

Legion
  • 3,922
  • 8
  • 51
  • 95