Reputation: 1985
I have the following packages and their dependencies installed in my WebAPI project:
Ninject.Web.WebApi
Ninject.Web.WebApi.OwinHost
I am running this purely as a web-api project. No MVC.
When I run my application and send a POST
to the AccountController's Register action I get the following error returned:
{
"message":"An error has occurred.",
"exceptionMessage":"An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor.",
"exceptionType":"System.InvalidOperationException",
"stackTrace":" at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()",
"innerException":{
"message":"An error has occurred.",
"exceptionMessage":"Type 'RPT.Api.Controllers.AccountController' does not have a default constructor",
"exceptionType":"System.ArgumentException",
"stackTrace":" at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
Can anyone help me as the only details I can find on Google seem to be from 2012.
Note: I've also tried AutoFac instead of Ninject and get the same error there too. Most frustrating.
Here's my NinjectWebCommon.cs:
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using RPT.Data;
using RPT.Services;
using RPT.Services.Interfaces;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(RPT.Api.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(RPT.Api.NinjectWebCommon), "Stop")]
namespace RPT.Api
{
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();
/// <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<RptContext>().ToSelf();
kernel.Bind<IUserStore<IdentityUser>>().To<UserStore<IdentityUser>>();
kernel.Bind<UserManager<IdentityUser>>().ToSelf();
kernel.Bind<IAccountService>().To<AccountService>();
}
}
}
Here's my AccountController:
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.ModelBinding;
using Microsoft.AspNet.Identity;
using RPT.Api.Models;
using RPT.Services.Interfaces;
namespace RPT.Api.Controllers
{
[RoutePrefix("api/account")]
public class AccountController : ApiController
{
#region Initialisation
private readonly IAccountService _accountService;
public AccountController(IAccountService accountService) : base()
{
_accountService = accountService;
}
#endregion
#region Actions
[AllowAnonymous]
[Route("register")]
public async Task<IHttpActionResult> Register(UserRegistrationViewModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var result = await _accountService.RegisterUser(model.UserName, model.Password);
var errorResult = GetErrorResult(result);
return errorResult ?? Ok();
}
#endregion
#region Internal
protected override void Dispose(bool disposing)
{
if (disposing)
{
_accountService.Dispose();
}
base.Dispose(disposing);
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
{
return InternalServerError();
}
if (result.Succeeded) return null;
if (result.Errors != null)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
if (ModelState.IsValid)
{
// No ModelState errors are available to send, so just return an empty BadRequest.
return BadRequest();
}
return BadRequest(ModelState);
}
#endregion
}
}
Upvotes: 27
Views: 35007
Reputation: 5279
As other answers have pointed out, the error message can be misleading. Ninject might be working fine, but it could be that some dependency cannot be instantiated for a variety of reasons, such as:
[Inject]
property).You do not see all details in the error returned by the server (which may be by design). If you attach the debugger, you may also not be able to catch the exception unless you disable "Just My Code" in the debugging settings. Then you may be able to catch an internal Ninject exception which may have all the information you need to understand the problem.
Older versions of Ninject, or if you are not using Ninject.Web.WebApi.WebHost
, also require that you register Ninject as a dependency resolver, as pointed out in https://stackoverflow.com/a/24196092/2279059.
Upvotes: 0
Reputation: 51
This applies to older versions of Ninject, or if you are not using the auto-generated bootstrap code from Ninject.Web.WebApi.Webhost
.
You are missing a dependency resolver, its a really basic implementation:
public class NinjectHttpDependencyResolver : IDependencyResolver, IDependencyScope
{
private readonly IKernel _kernel;
public NinjectHttpDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return this;
}
public void Dispose()
{
//Do nothing
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType);
}
}
Then just register it when you create the kernel:
var httpResolver = new NinjectHttpDependencyResolver(kernel);
GlobalConfiguration.Configuration.DependencyResolver = httpResolver;
Upvotes: 2
Reputation: 378
I've got a situation where I have a service, and into it injected other services. One of these injected services had another injected services, and one of them was not registered properly for dependency injection.
I set a breakpoint in the constructor of services that were injected in controller (services before one that was causing a problem). In debugging it was shown for which service it cannot resolve the dependency.
Upvotes: 0
Reputation: 2809
I too was trying to make an 'only API' app, but faced similar issues. For me personally, in the end it came down the selecting the right starting template.
Despite going for API-only, when in the 'Create a new ASP.NET Web Application" wizard, selecting the 'Empty' application-type and choosing MVC and Web API in the 'add folders & core references' section made Ninject work fine:
As opposed to the 'Web API' application, which didn't play nice with Ninject:
After that, it's simply to add the Ninject.Web.WebApi.WebHost package, which adds the NinjectWebCommon.cs class, and start adding dependencies.
Upvotes: 0
Reputation: 881
What worked for me was adding the NuGet package Ninject.Web.WebApi.WebHost
as described here: https://github.com/ninject/Ninject.Web.WebApi/wiki/Setting-up-an-mvc-webapi-application
Upvotes: 6
Reputation: 985
For me, what caused this error was that for the interface I was passing into the constructor, I had a named binding and I called it with the wrong name. As you can see the below, the binding says it's named "Warehouse", but I got things mixed up and put "DataWarehouse" in the constructor. Getting this straightened out caused the error about a parameterless constructor to go away.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IVisitProcessor>().To<VisitProcessor>().InThreadScope();
kernel.Bind<IPatientProcessor>().To<PatientProcessor>().InThreadScope();
kernel.Bind<IDbConnectionFactory>().To<SqlConnectionFactory>().Named("Warehouse").WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["DataWarehouse"].ConnectionString);
}
constructor:
//WRONG NAME
public VisitProcessor([Named("DataWarehouse")] IDbConnectionFactory connection)
{
_database = connection;
}
Upvotes: 0
Reputation: 104
Make sure you have registered all the types used by the controller, all the way down to the database.
In my case, I had only added the interface that the controller itself used, but not the interface used to actually query the database.
Notice in the code below how the AddUserMaintenanceProcessor class has dependencies that the controller does not know about. If you omit the Unity (or whatever IoC tool you use) type mappings for these dependencies, the controller construction will fail.
My solution uses Unity, but the point I'm trying to make is that you need to create type mappings for all dependencies.
Startup.cs
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
// Configure Unity
var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
GlobalConfiguration.Configuration.DependencyResolver = resolver;
config.DependencyResolver = resolver;
// Do Web API configuration
WebApiConfig.Register(config);
app.UseWebApi(config);
}
UnityConfig.cs
public class UnityConfig
{
private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
// Gets the configured Unity container
public static IUnityContainer GetConfiguredContainer()
{
return Container.Value;
}
// Register type mappings
public static void RegisterTypes(IUnityContainer container)
{
// LogManagerAdapter wrapping e.g. log4net
container.RegisterType<ILogManager, LogManagerAdapter>();
// AutoMapperAdapter wrapping e.g. AutoMapper (configuration omitted)
container.RegisterType<IAutoMapper, AutoMapperAdapter>();
// Interface for persisting the user
container.RegisterType<IAddUserQueryProcessor, AddUserQueryProcessor>();
// Interface for doing application logic in regards to adding a user
container.RegisterType<IAddUserMaintenanceProcessor, AddUserMaintenanceProcessor>();
}
}
UsersController.cs
public class UsersController : ApiController
{
private readonly IAddUserMaintenanceProcessor _addUserProcessor;
public UsersV1Controller(IAddUserMaintenanceProcessor addUserProcessor)
{
_addUserProcessor = addUserProcessor;
}
public async Task<UserModel> Post(NewUser user)
{
return await _addUserProcessor.AddUserAsync(user);
}
// ...
}
AddUserMaintenanceProcessor.cs
public class AddUserMaintenanceProcessor : IAddUserMaintenanceProcessor
{
private readonly IAddUserQueryProcessor _queryProcessor;
private readonly ILog _logger;
private readonly IAutoMapper _mapper;
public AddUserMaintenanceProcessor(
IAddUserQueryProcessor queryProcessor,
ILogManager logManager,
IAutoMapper mapper)
{
_queryProcessor = queryProcessor;
_logger = logManager.GetLog(typeof(AddUserMaintenanceProcessor));
_mapper = mapper;
}
public async Task<UserModel> AddUserAsync(NewUser newUser)
{
_logger.Info($"Adding new user {newUser.UserName}");
// Map the NewUser object to a User object
var user = _mapper.Map<User>(newUser);
// Persist the user to a medium unknown to this class, using the query processor,
// which in turn returns a User object
var addedUser = await _queryProcessor.AddUserAsync(user);
// Map the User object back to UserModel to return to requester
var userModel = _mapper.Map<UserModel>(addedUser);
_logger.Info($"User {userModel.UserName} added successfully");
return userModel;
}
}
I have omitted the interfaces for the processors as they only contain one method (Strategy pattern). The interfaces for logging and auto mapping are irrelevant to this question.
The AddUserQueryProcessor class simply persists the user to the database. Once again irrelevant to this question.
Upvotes: 2
Reputation: 25349
In my case, the reason was resolver could not find a mapping. That is suppose say HomeController has a dependency on IDumb, the resolver could not find a concrete implementation of Dumb with implements IDumb. In other words the error message
**No parameterless constructor defined for this object
An error occurred when trying to create a controller of type 'ToDoListT1.WebApp.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor**
is completely misleading. In my case I just resolved by adding a reference to the project of the class Dumb. It should have been something like "No mapping for IDumb could be found.". I am not sure the problem is with NInject or MS. What ever it took me hours to find this out.
Upvotes: 17
Reputation: 4783
Did you modify your OWIN Startup
class to call app.UseNinjectWebApi
and app.UseNinjectMiddleware
rather than calling app.UseWebApi
?
Startup.cs in the Ninject Web API samples does this...
Upvotes: 21