15

Ecco la traccia:MVC 4 Web Api Controller non ha un costruttore predefinito?

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

Ho trovato questo strano come public class UsersController : ApiController { ... } sta lavorando bene. Ho confrontato i 2 controller, tutte le impostazioni e le strutture sono simili.

Sto usando Ninject e ho il mio sistema di installazione simile a Jamie KurtzAsp.Net Mvc 4 and the Web Api: Building a REST Service from Start to Finish.

Dalla traccia stack, c'è qualcuno in grado di individuare il problema e come risolverlo? Grazie!

Come richiesto.

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: funziona bene.

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

Sto usando NinjectWebCommon.cs e in essa, ho questo e pochi altri metodi predefiniti .:

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

      GlobalConfiguration.Configuration.MessageHandlers.Add(kernel.Get<BasicAuthenticationMessageHandler>()); 
     } 

allora ho 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>();  
      ......... 
     } 
    ....... 
} 

Sia NinjectWebCommon.cs e NinjectConfigurator.cs sono situato nella cartella App_Start.

container.Bind<ISession>().ToMethod(CreateSession); è NHibernate. È compreso tra NinjectConfigurator.cs all'interno di private void ConfigureNHibernate(IKernel container) { ... }

+0

Lo stacktrace non è sufficiente per scoprire qual è il tuo problema, quindi per favore pubblica il codice del tuo 'ContinentsController'! – nemesv

+0

Hai copiato il codice di 'ContinentsController' due volte ... ma qualunque cosa. Il problema è che una delle sessioni di sessione delle dipendenze del tuo contructor, IContinentMapper continentMapper, IHttpContinentFetcher continentFetcher, IDateTime dateTime' non è registrata in Ninject. Assicurati che tutto sia registrato o pubblica i binding del kernel per farci sapere cosa manca. E il tuo UserController funziona bene perché ha un insieme di dipendenze completamente diverso. – nemesv

+0

@nemesv Ho aggiunto quello che hai richiesto. – Komengem

risposta

14

Questo errore è un errore noto quando non si imposta il resolver di dipendenza nell'applicazione. Controller Factory non è riuscito a trovare un costruttore senza parametri per creare il controller ed eseguire il metodo di azione (o metodo verb?). Quindi, devi creare una classe resolver di dipendenza e impostarla sull'inizializzazione della tua app web. Risolverà le dipendenze dei tuoi controller.

Utilizzando ninject, si potrebbe provare qualcosa di simile:

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 prende un oggetto Ninject StandardKernel come argomento del costruttore ed è usato questo riferimento ogni volta che un ambito dipendenza è pipeline. Per rendere questo tutto il lavoro, la classe NinjectDependencyResolver viene assegnato alla configurazione globale dell'applicazione:

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

Sul file Global.asax.cs alla fine della manifestazione Application_Start, chiamare questo metodo CreateKernel.

+3

Ho dovuto aggiungere semplicemente 'GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver (kernel); 'al mio NinjectWebCommon, non ha dovuto chiamare il metodo in global.asax.cs. Grazie – Jaanus

2

Ho anche incontrato questo errore identico ma da un'altra causa utilizzando Ninject. In realtà avevo il resolver di dipendenza e la configurazione corretta. Infatti l'app funzionava bene fino a quando non ho provato a risolvere un'altra nuova dipendenza. Avevo il set di registrazione per questo, quindi non riuscivo a capire cosa mancasse.

Il problema era che accidentalmente risolsi l'interfaccia al stessa interfaccia invece di risolvere al tipo concreto corretta. Quindi, utilizzando un esempio dalla OP Ho fatto la seguente, che genera l'errore identico:

container.Bind<IUserManager>().To<IUserManager>(); 

Avviso risolvere a IUserManager che era una svista, ma lo fa portare all'errore identico dall'OP. Ovviamente la soluzione è risolvere il tipo concreto corretto.

13

È necessario indicare a Ninject come risolvere correttamente le dipendenze dell'API Web.

Puoi usare la risposta di Felipe Oriani, ma se ti piace c'è un pacchetto NuGet chiamato WebApiContrib.IoC.Ninject che lo farà per te.

  1. In Visual Studio Vai a: Strumenti> NuGet Package Manager> Gestisci Pacchetti Nuget per soluzione

  2. Installare il pacchetto WebApiContrib.IoC.Ninject

  3. Edit: NinjectWebCommon.cs e aggiornare il metodo CreateKernel() per includere: 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; 
        } 
    } 
    
+1

hey man! grazie, funziona perfettamente con la mia applicazione webApi. MVC 5. – willyMon

+1

grazie amico, grazie mille, è stato un grande aiuto felice codifica: d –

0

Ho avuto questo problema, anche, ma appena scoperto che uno dei miei interfacce non siano state effettivamente attuate da tutte le classi (ho dimenticato di aggiungere alla dichiarazione della classe).

1

La risposta accettata è del 2014. Dato che molte persone hanno avuto questo problema, dal 2016 c'è una ricetta per questo. Questo aggiunge solo alla risposta accettata.

Il modo in cui lo faccio è installando i pacchetti Ninject.MVC3 e WebApiContrib.IoC.Ninject. Un file chiamato NinjectWebCommon viene aggiunto alla tua cartella App_Start. È quindi possibile utilizzare lo strumento integrato NinjectResolver.

Basta aggiungere questo metodo:

private static void AddWebApiSupport(StandardKernel kernel) 
{ 
    // Support WebAPI 
    GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel); 
    GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider), new NinjectWebApiFilterProvider(kernel)); 
} 

e chiamare prima di chiamare RegisterServices.

0

Questo è un problema comune soprattutto quando si lavora con il contenitore di iniezione di dipendenze di Ninject. Seguire i passaggi per risolvere questo problema.  Make sure you have Installed the following packages.

nuovo andare per questo e Installare questo- enter image description here

Ora controllare il l'App_start folder.You troverà la seguente cosa (NinjectWebcommon.cs).Metodo enter image description here

Ora doppio clic e controllare la seguente riga nel CreateKernel() come questo

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

E poi Pubblica il tuo dependincy come questo

private static void RegisterServices(IKernel kernel) 
    { 

     kernel.Bind<IProductDetails>().To<ProductDetails>().InRequestScope(); 
    }  

Sono sicuro che questo renderà la vostra soluzione lavoro.

0
private static void RegisterServices(IKernel kernel) 
     { 
      kernel.Bind<ICountingKsRepository>().To<CountingKsRepository>(); 

Assicurarsi che il Per <> parte è una classe concreta non un'interfaccia, come che creerà lo stesso errore anche!

Problemi correlati