1

I have already researched a number of errors based on the message "Make sure that the controller has a parameterless public constructor" and those answers did not appear to help. (see bottom)

Building an ASP.NET WEB API 2 application using Ninject. I want to have an applicationController which will be polled from an Angular service to allow sharing some information across sessions. To accomplish this I have built an applicationService designed to be run as a singleton so that each web api session will share the same service. I am using Ninject 3.2.0.0 and have installed (using NPM based on these instructions)

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

Which, by design, created the NinjectWebCommon where I have added the (I believe) necessary bindings. During an initial request the applicationService is instantiated (as expected), but when the call is made to the GET method of the applicationController I get:

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

the stack trace reveals:

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 fact that it is calling DefaultHttpControllerActivator makes me think that the Ninject Bindings are not correct, but the the only way the applicationService could be instantiated would be due to ninject.

The bindings in NinjectWebCommon

    private static void RegisterServices(IKernel kernel)
   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<ScfProvider>().ToSelf().InSingletonScope();
            kernel.Bind<ApplicationService>().ToSelf().InSingletonScope().WithConstructorArgument(kernel.Get<ScfProvider>());
            kernel.Bind<ApplicationController>().ToSelf().InRequestScope().WithConstructorArgument(kernel.Get<ApplicationService>());
        }        
    }

the ApplicationService:

    public sealed class ApplicationService
    {
        private readonly ICommand _scfUpdater;
        private Timer _timer;

        public ApplicationService(ScfProvider scfUpdater)
        {
            if (scfUpdater == null) throw new ArgumentNullException(nameof(scfUpdater));
            _scfUpdater = scfUpdater;
            _activeUsers = new Dictionary<string, string>();
            int scfInterval = int.Parse(ConfigurationManager.AppSettings["SCFUpdateInterval"]);
            _timer = new Timer(SCFTick, this, 0, scfInterval);
        }

#if DEBUG
        public ICommand SCFUpdater => _scfUpdater;
#endif



        private void SCFTick(object state)
        {
            _scfUpdater.Execute();
        }

        private readonly Dictionary<string, string> _activeUsers;
        public Dictionary<string, string> ActiveUsers => _activeUsers;

        public void UpdateUser(string userName, string status)
        {
            if (_activeUsers.ContainsKey(userName))
            {
                _activeUsers[userName] = status;
            }
            else
            {
                _activeUsers.Add(userName, status);
            }
        }
}

and finally, the applicationController:

public class ApplicationController : ApiController


 {
        private readonly ApplicationService _applicationService;
        public ApplicationController(ApplicationService applicationService)
        {
            _applicationService = applicationService;
        }

        // GET: api/application
        public IHttpActionResult Get()
        {
            _applicationService.UpdateUser(User.Identity.Name, "online");
            return Ok(_applicationService.ActiveUsers);
        }
...
}

(note: once I have this working more complex functionality will be added...but I need this working first...)

Other research: Parameterless constructor error with Ninject bindings in .NET Web Api 2.1 (I have the correct references and a public c'tor)

Ninject Web Api "Make sure that the controller has a parameterless public constructor." (& several similar) (As I understand it, WebActivatorEx and NinjectWebCommon resolve this matter)

Community
  • 1
  • 1
Cos Callis
  • 5,051
  • 3
  • 30
  • 57
  • Please show your `IDependencyResolver` or `IHttpControllerActivator` registration. – Steven Aug 30 '16 at 16:16
  • I have edited in additional material to the NinjectWebCommon (above). I believe that the the CreateKernel() method replaces the need for IDependencyResolver or IHttpControllerActivator. (or at least it was absent from the example code provided at the first link I showed above) – Cos Callis Aug 30 '16 at 16:38
  • I think that this NinjectWebCommon library is built for MVC, not for Web API. – Steven Aug 30 '16 at 16:52
  • What I have read suggests otherwise (if I remove it the NinjectWebCommon class will no longer compile...) I believe the root of my problem lies in the combination of ninject elements and versions along with various articles and samples that just don't quite align with each other or what I am doing. – Cos Callis Aug 30 '16 at 17:02

1 Answers1

1

I have recently ran into the problem with the parameterless constructor. Having wasted time googling for solutions with solutions that were ok locally but didn't work when deployed the step I took were these.

Uninstalled nugets for Ninject.* double checked bin folder and deleted any Ninject*.dlls Commented out all code in the Ninject.Web.Common.cs files and renamed it as I wanted to keep service bindings etc.. so I could reinstate in the Ninject.Web.Common.cs that would be created after reinstating the Ninject* nuget packages.

I then followed this guide but using the lates Ninject* nuget versions.

https://nodogmablog.bryanhogan.net/2016/04/web-api-2-and-ninject-how-to-make-them-work-together/

do not forget to add this in the newly created Ninject.Web.Common

GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

before return kernel; in the private static CreateKernel method.

Barry S
  • 41
  • 3