Voici la trace:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'ProjectName.Web.Api.Controllers.ContinentsController' does not have a default constructor
</ExceptionMessage>
<ExceptionType>System.ArgumentException</ExceptionType>
<StackTrace>
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)
</StackTrace>
</Error>
Je trouve cela bizarre car public class UsersController : ApiController { ... }
fonctionne très bien. J'ai comparé les 2 contrôleurs, tous les paramètres et structures sont similaires.
J'utilise Ninject
et la configuration de mon système est similaire à Jamie Kurtz
Asp.Net Mvc 4 et Web Api: création d'un service REST de bout en bout }.
À partir de la trace de la pile, est-ce que quelqu'un peut repérer le problème et comment le résoudre? Merci!
Tel que demandé.
ContinentsController
[LoggingNHibernateSession]
public class ContinentsController : ApiController
{
private readonly ISession _session;
private readonly IContinentMapper _continentMapper;
private readonly IHttpContinentFetcher _httpContinentFetcher;
private readonly IDateTime _dateTime;
public ContinentsController(ISession session, IContinentMapper continentMapper, IHttpContinentFetcher continentFetcher, IDateTime dateTime)
{
_session = session;
_continentMapper = continentMapper;
_httpContinentFetcher = continentFetcher;
_dateTime = dateTime;
}
public IEnumerable<Continent> Get()
{
var continents = _session
.Query<Data.Model.Continent>()
.Select(_continentMapper.CreateContinent)
.ToList();
return continents;
}
public Continent Get(long id)
{
var modelContinent = _httpContinentFetcher.GetContinent(id);
var continent = _continentMapper.CreateContinent(modelContinent);
return continent;
}
}
UsersController: Fonctionne très bien.
public class UsersController : ApiController
{
private readonly ISession _session;
private readonly IUserManager _userManager;
private readonly IUserMapper _userMapper;
private readonly IHttpUserFetcher _userFetcher;
public UsersController(
IUserManager userManager,
IUserMapper userMapper,
IHttpUserFetcher userFetcher,
ISession session)
{
_userManager = userManager;
_userMapper = userMapper;
_userFetcher = userFetcher;
_session = session;
}
[Queryable]
public IQueryable<Data.Model.User> Get()
{
return _session.Query<Data.Model.User>();
}
[LoggingNHibernateSession]
public User Get(Guid id)
{
var user = _userFetcher.GetUser(id);
return _userMapper.CreateUser(user);
}
}
J'utilise NinjectWebCommon.cs
et dans celui-ci, j'ai ceci et quelques autres méthodes par défaut .:
private static void RegisterServices(IKernel kernel)
{
var containerConfigurator = new NinjectConfigurator();
containerConfigurator.Configure(kernel);
GlobalConfiguration.Configuration.MessageHandlers.Add(kernel.Get<BasicAuthenticationMessageHandler>());
}
Alors j'ai NinjectConfigurator.cs
:
public class NinjectConfigurator
{
......
private void AddBindings(IKernel container)
{
.....
container.Bind<IDateTime>().To<DateTimeAdapter>();
container.Bind<IDatabaseValueParser>().To<DatabaseValueParser>();
//HttpFetchers
container.Bind<IHttpUserFetcher>().To<HttpUserFetcher>();
container.Bind<IHttpContinentFetcher>().To<HttpContinentFetcher>();
//TypeMappers
container.Bind<IUserManager>().To<UserManager>();
container.Bind<IMembershipInfoProvider>().To<MembershipAdapter>();
container.Bind<IUserMapper>().To<UserMapper>();
container.Bind<IContinentMapper>().To<ContinentMapper>();
.........
}
.......
}
NinjectWebCommon.cs
et NinjectConfigurator.cs
se trouvent tous deux dans le dossier App_Start
.
container.Bind<ISession>().ToMethod(CreateSession);
est NHibernate
. C'est dans NinjectConfigurator.cs
dans private void ConfigureNHibernate(IKernel container) { ... }
Cette erreur est une erreur connue lorsque vous ne définissez pas le résolveur de dépendances dans votre application. La Controller Factory n'a pas pu trouver de constructeur sans paramètre pour créer le contrôleur et exécuter la méthode d'action (ou la méthode verb??). Vous devez donc créer une classe de résolveur de dépendances et la définir lors de l'initialisation de votre application Web. Cela résoudra les dépendances de vos contrôleurs.
En utilisant ninject
, vous pouvez essayer quelque chose comme ceci:
using Ninject;
using Ninject.Syntax;
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Web.Http.Dependencies;
namespace MyApplication.App_Start
{
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
}
La classe NinjectDependencyResolver
prend un objet Ninject StandardKernel
comme argument de constructeur et cette référence est utilisée chaque fois qu'une portée de dépendance est mise en pipeline . Pour que tout cela fonctionne, la classe NinjectDependencyResolver
est affectée à la configuration globale de l'application:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
// register all your dependencies on the kernel container
RegisterServices(kernel);
// register the dependency resolver passing the kernel container
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
Dans votre fichier Global.asax.cs
à la fin de l'événement Application_Start, appelez cette méthode CreateKernel
.
Vous devez indiquer à Ninject comment résoudre correctement les dépendances de l'API Web.
Vous pouvez utiliser la réponse de Felipe Oriani, mais si vous le souhaitez, il existe un package NuGet appelé WebApiContrib.IoC.Ninject qui le fera pour vous.
Dans Visual Studio, accédez à: Outils> Gestionnaire de paquets NuGet> Gérer Packages NuGet pour solution
Installez le WebApiContrib.IoC.Ninject package
Edit: NinjectWebCommon.cs et mettez à jour la méthode CreateKernel () pour inclure: 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;
}
}
J'ai également rencontré cette erreur identique mais provenant d'une autre cause en utilisant Ninject
. En fait, le résolveur de dépendance et la configuration étaient corrects. En fait, l'application fonctionnait bien jusqu'à ce que j'essaye de résoudre une autre nouvelle dépendance. J'avais l'enregistrement prévu pour cela, donc je ne pouvais pas comprendre ce qui manquait.
Le problème était que j'ai accidentellement résolu l'interface avec le même interface, par opposition à la résolution avec le type de béton approprié. Donc, en utilisant un exemple de l’OP, j’ai fait ce qui suit: c’est la même erreur:
container.Bind<IUserManager>().To<IUserManager>();
Avis résolvant en IUserManager
qui était un oubli, mais ne conduit à la même erreur de la part du PO. Évidemment, la solution consiste à résoudre le type de béton approprié.
La réponse acceptée est celle de 2014. Étant donné que de nombreuses personnes ont eu ce problème, à partir de 2016, il existe une recette pour cela. Ceci ne fait qu'ajouter à la réponse acceptée.
Je le fais en installant les paquets Ninject.MVC3
et WebApiContrib.IoC.Ninject
. Un fichier appelé NinjectWebCommon
est ajouté à votre dossier App_Start
. Vous pouvez ensuite utiliser la variable NinjectResolver
intégrée.
Ajoutez simplement cette méthode:
private static void AddWebApiSupport(StandardKernel kernel)
{
// Support WebAPI
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider), new NinjectWebApiFilterProvider(kernel));
}
et appelez-le avant d'appeler RegisterServices
.
Pour moi, il suffisait d'ajouter le paquet Ninject.Web.WebApi.Webhost NuGet.
Pour mes applications utilisant à la fois MVC et WebApi2, j'ai les packages suivants pour Ninject:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICountingKsRepository>().To<CountingKsRepository>();
Assurez-vous que la partie To <> est une classe concrète et non une interface, car cela créera également la même erreur!
J'ai eu ce problème aussi, mais il s'est avéré qu'une de mes interfaces n'était implémentée par aucune classe (j'ai oublié de l'ajouter à la déclaration de classe).
Il s'agit d'un problème courant qui se produit principalement lorsque vous travaillez avec Ninject Dependency injection Container . Veuillez suivre les étapes pour résoudre ce problème .
Encore une fois, optez pour ceci et installez-le-
Maintenant, vérifiez le dossier App_start.Vous trouverez la chose suivante (NinjectWebcommon.cs) .
Maintenant, double-cliquez et vérifiez la ligne suivante dans la méthode CreateKernel () comme ceci
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);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
Et puis enregistrez votre dépendance comme ça
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IProductDetails>().To<ProductDetails>().InRequestScope();
}
Je suis sûr que cela fera fonctionner votre solution.