Controller does not have a default constructor - Ninject, Owin, Web Api

3.6k Views Asked by At

I'm migrating an MVC/WebApi application to using Owin, but after installing all the components, and moving all configuration from the globals.asax to Startup.cs i'm getting the error Type 'EventController' does not have a default constructor.

It seems how i've got ninject configured isn't working correctly. Can anyone spot the error?

EventController

public class EventController : BaseApiController
{
    private readonly IAttendeeService attendeeService;
    private readonly IEventService eventService;
    private readonly IExcelService excelService;

    public EventController(IEventService eventService, IAttendeeService attendeeService, IExcelService excelService)
    {
        this.attendeeService = attendeeService;
        this.eventService = eventService;
        this.excelService = excelService;
    }
}

Here's the startup.cs class

using System.Linq;
using System.Net.Http.Formatting;
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Filanthropy.Core;
using Filanthropy.Model.Models;
using Filanthropy.Services;
using Filanthropy.Web;
using Filanthropy.Web.App_Start;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Newtonsoft.Json.Serialization;
using Ninject;
using Ninject.Web.Common;
using Ninject.Web.Common.OwinHost;
using Ninject.Web.WebApi.OwinHost;
using Owin;

[assembly: OwinStartup(typeof(Startup))]
namespace Filanthropy.Web
{
    public partial class Startup
    {

        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration httpConfig = new HttpConfiguration();

            ConfigureOAuthTokenGeneration(app);

            ConfigureWebApi(httpConfig);

            app.UseCors(CorsOptions.AllowAll);

            app.UseWebApi(httpConfig);

            app.MapSignalR();

            app.UseNinjectMiddleware(CreateKernel).UseNinjectWebApi(httpConfig);


            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AutoMapperConfig.Configure();
        }

        private void ConfigureOAuthTokenGeneration(IAppBuilder app)
        {
            // Configure the db context and user manager to use a single instance per request
            app.CreatePerOwinContext(FilanthropyContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

            // Plugin the OAuth bearer JSON Web Token tokens generation and Consumption will be here

        }

        private void ConfigureWebApi(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
               name: "DefaultApi",
               routeTemplate: "api/{controller}/{id}",
               defaults: new { id = RouteParameter.Optional }
               );

            var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        }

        private static StandardKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.Load(Assembly.GetExecutingAssembly());

            RegisterServices(kernel);
            return kernel;
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IDbContext>().To<FilanthropyContext>().InRequestScope();
            kernel.Bind<IEventService>().To<EventService>().InRequestScope();
            kernel.Bind<IAttendeeService>().To<AttendeeService>().InRequestScope();
            kernel.Bind<IProjectService>().To<ProjectService>().InRequestScope();
            kernel.Bind<IPaymentService>().To<PaymentService>().InRequestScope();
            kernel.Bind<IPledgeService>().To<PledgeService>().InRequestScope();
            kernel.Bind<IExcelService>().To<ExcelService>();

            kernel.Bind<IUserStore<ApplicationUser>>()
                .To<UserStore<ApplicationUser>>()
                .WithConstructorArgument("context", context => kernel.Get<FilanthropyContext>());
        }       


    }
}
3

There are 3 best solutions below

0
On

The error message

Controller does not have a default constructor

can be misleading, because you may also see it in a lot of other situations when there is nothing wrong with the controller or the way Ninject is set up.

Try again with a more simple controller, which only has a single dependency, which

  • Has no other dependencies
  • Has a public default constructor and no other constructors

Does this work? Then, most likely, there is something wrong with your other dependencies, such as:

  • A dependency has no (public) default constructor.
  • A dependency is not registered in RegisterServices.
  • One or more dependencies have one or more dependencies with one or more of the problems above.
  • A dependency DOES have a usable constructor, but also has another constructor, which (for whatever reason) only takes interfaces of registered services, and which is neither usable, nor intended to be used by dependency injection.

All problems with setting up Ninject that I've had were due to bogus dependencies, and this is not unlikely if you add Ninject (or dependency injection) to a project "late", and you have to refactor to make it testable.

Do not modify the NinjectWebCommon.cs file, other than adding service registrations. As long as you have installed all the required packages:

  • Ninject
  • Ninject.Web.Common
  • Ninject.Web.Common.WebHost
  • Ninject.Web.WebApi
  • Ninject.Web.WebApi.WebHost

then Ninject should work without modifications, and any of the modifications suggested in other answers or other questions will only create new problems and send you on a round-trip through StackOverflow questions asked by people who tried these modifications and ran into problems.

0
On

I know this is a old thread and have solutions marked as answers, but none of these worked for me and found another solution that worked for me. Posting it for others who still might be facing the problem.

I am using ASP.NET MVC 5 with VS 2017 and Ninject. I implemented all suggestions mentioned in this thread but I was still getting the 'does not have a default constructor' runtime error. I installed Ninject.MVC5 nuget package and it worked.

3
On

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

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