wake-up-neo.net

MVC 4 Web Api Controller hat keinen Standardkonstruktor?

Hier ist die Spur:

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

Ich finde das komisch, da public class UsersController : ApiController { ... } gut funktioniert. Ich habe die 2 Controller verglichen, alle Einstellungen und Strukturen sind ähnlich.

Ich verwende Ninject und habe mein System ähnlich eingerichtet wie Jamie KurtzAsp.Net Mvc 4 und Web Api: Erstellen eines REST Dienstes von Anfang bis Ende .

Kann jemand anhand der Stack-Ablaufverfolgung das Problem erkennen und wie man es lösen kann? Vielen Dank!

Wie angefordert.

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: Funktioniert gut.

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

Ich verwende NinjectWebCommon.cs, und ich habe hier und einige andere Standardmethoden:

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

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

Dann habe ich 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>();    
            .........
        }
     .......
}

Sowohl NinjectWebCommon.cs als auch NinjectConfigurator.cs befinden sich im Ordner App_Start

container.Bind<ISession>().ToMethod(CreateSession); ist NHibernate. Es ist innerhalb von NinjectConfigurator.cs in private void ConfigureNHibernate(IKernel container) { ... }

16
Komengem

Dieser Fehler ist ein bekannter Fehler, wenn Sie den Abhängigkeitsauflöser in Ihrer Anwendung nicht festlegen. Die Controller Factory konnte keinen parameterlosen Konstruktor zum Erstellen des Controllers und zum Ausführen der Aktionsmethode (oder Verbmethode?) Finden. Daher müssen Sie eine Abhängigkeitsauflösungsklasse erstellen und bei der Initialisierung Ihrer Web-App festlegen. Es löst Abhängigkeiten Ihrer Controller auf.

Mit ninject können Sie Folgendes versuchen:

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

Die NinjectDependencyResolver-Klasse verwendet ein Ninject StandardKernel-Objekt als Konstruktorargument, und diese Referenz wird immer dann verwendet, wenn ein Abhängigkeitsbereich in eine Pipeline geschrieben wird ..__ Damit dies funktioniert, wird die NinjectDependencyResolver-Klasse der globalen Konfiguration der Anwendung zugewiesen:

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

Rufen Sie in Ihrer Global.asax.cs-Datei am Ende des Application_Start-Ereignisses diese CreateKernel-Methode auf.

16
Felipe Oriani

Sie müssen Ninject mitteilen, wie die Abhängigkeiten der Web-API richtig aufgelöst werden. 

Sie können Felipe Orianis Antwort verwenden, aber wenn Sie möchten, gibt es ein NuGet-Paket namens WebApiContrib.IoC.Ninject, das dies für Sie erledigt.

  1. In Visual Studio Gehen Sie zu: Tools> NuGet Package Manager> Verwalten NuGet-Pakete für Lösung

  2. Installieren Sie das Paket WebApiContrib.IoC.Ninject

  3. Edit: NinjectWebCommon.cs und aktualisieren Sie die CreateKernel () - Methode, um Folgendes aufzunehmen: 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;
        }
    }
    

Ich bin auch auf diesen identischen Fehler gestoßen, aber aus einer anderen Ursache mit Ninject. Ich hatte tatsächlich die korrekte Abhängigkeitsauflösung und Konfiguration. Tatsächlich funktionierte die App gut, bis ich versuchte, eine weitere neue Abhängigkeit aufzulösen. Ich hatte die Registrierung dafür festgelegt, sodass ich nicht herausfinden konnte, was fehlte.

Das Problem war, dass ich versehentlich die Schnittstelle in die gleiche Schnittstelle aufgelöst habe, anstatt in den richtigen konkreten Typ aufzulösen. Anhand eines Beispiels aus dem OP habe ich folgendes gemacht, was zu dem identischen Fehler führt:

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

Beachten Sie, dass das Auflösen in IUserManager ein Versehen war, aber es zu dem identischen Fehler aus dem OP führt . Offensichtlich besteht die Lösung darin, den richtigen konkreten Typ zu finden.

2
atconway

Die akzeptierte Antwort stammt aus dem Jahr 2014. Da viele Menschen diese Ausgabe hatten, gibt es seit 2016 ein Rezept dafür. Dies fügt nur die akzeptierte Antwort hinzu.

Wie ich das mache, ist die Installation der Pakete Ninject.MVC3 und WebApiContrib.IoC.Ninject. Eine Datei mit dem Namen NinjectWebCommon wird Ihrem App_Start-Ordner hinzugefügt. Sie können dann die integrierte NinjectResolver verwenden.

Fügen Sie einfach diese Methode hinzu:

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

und rufen Sie es auf, bevor Sie RegisterServices aufrufen.

1
andrei.ciprian

Für mich war es nur eine Frage des Hinzufügens des Ninject.Web.WebApi.Webhost NuGet-Pakets.

Für meine Anwendungen, die sowohl MVC als auch WebApi2 verwenden, habe ich folgende Pakete für Ninject:

  • Ninject
  • Ninject.MVC5
  • Ninject.Web.Common
  • Ninject.Web.Common.WebHost
  • Ninject.Web.WebApi
  • Ninject.Web.WebApi.WebHost
1
Jamie M

Es geschah bei mir, als ich die Schnittstelle und die Klasse für die Abhängigkeitsinjektion in der Datei web.config nicht erwähnte.

0
Mehul Parmar

Für den Fall, dass SimpleInjector Benutzer hier landen ...

Für mich war es einfach so, dass ich vergessen hatte, SimpleInjectorInitializer.Initialize(); zu meiner Application_Start() -Methode hinzuzufügen.

Normalerweise erstelle ich in diesen Tagen eine SimpleInjectorInitializer -Klasse im Ordner App_Start, In der ich die container.Verify()- und GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); -Aufrufe durchführe; nachdem ich meine GetInitializeContainer() -Methode aufgerufen habe, die alle Typregistrierungen usw. durchführt.

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

Stellen Sie sicher, dass der To-Teil eine konkrete Klasse und keine Schnittstelle ist, da dies den gleichen Fehler verursacht.

0
Andrew Day

Ich hatte auch dieses Problem, aber es stellte sich heraus, dass eines meiner Interfaces nicht von Klassen implementiert wurde (ich habe vergessen, es der Klassendeklaration hinzuzufügen).

0
Mark Cidade

Dies ist ein häufiges Problem, das hauptsächlich bei der Arbeit mit Ninject Dependency Injection Container auftritt. Bitte befolgen Sie die Schritte, um dieses Problem zu beheben.  Make sure you have Installed the following packages.

Gehen Sie noch einmal für diese und installieren Sie diese enter image description here

Überprüfen Sie nun den Ordner App_start. Sie finden folgendes (NinjectWebcommon.cs). enter image description here

Doppelklicken Sie nun und überprüfen Sie die folgende Zeile in der CreateKernel () -Methode

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

Und dann registrieren Sie Ihre Abhängigkeit wie folgt

 private static void RegisterServices(IKernel kernel)
    {

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

Ich bin sicher, dass dies Ihre Lösung zum Funktionieren bringen wird.

0
Debendra Dash