MVC5, Web API 2 und Ninject

72

Ich habe ein neues MVC5-Projekt mit Web-API 2 erstellt und dann das Ninject.MVC3-Paket von NuGet hinzugefügt.

Die Konstruktorinjektion funktioniert gut für die MVC5-Controller, aber ich erhalte eine Fehlermeldung, wenn ich versuche, sie mit den Web-API-Controllern zu verwenden.

Beim Versuch, einen Controller vom Typ 'UserProfileController' zu erstellen, ist ein Fehler aufgetreten. Stellen Sie sicher, dass der Controller über einen parameterlosen öffentlichen Konstruktor verfügt.

Konstruktor für den funktionierenden MVC5-Controller:

public class HomeController : Controller
{
    private IMailService _mail;
    private IRepository _repo;

    public HomeController(IMailService mail, IRepository repo)
    {
        _mail = mail;
        _repo = repo;
    }
}

Konstruktor für nicht funktionierenden Web-API-Controller:

public class UserProfileController : ApiController
{
    private IRepository _repo;

    public UserProfileController(IRepository repo)
    {
        _repo = repo;
    }
}

Unten finden Sie die vollständige Datei NinjectWebCommon.cs:

[assembly: WebActivator.PreApplicationStartMethod(typeof(DatingSite.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(DatingSite.App_Start.NinjectWebCommon), "Stop")]

namespace DatingSite.App_Start
{
using System;
using System.Web;

using Microsoft.Web.Infrastructure.DynamicModuleHelper;

using Ninject;
using Ninject.Web.Common;
using DatingSite.Services;
using DatingSite.Data;

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();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
#if DEBUG
        kernel.Bind<IMailService>().To<MockMailService>().InRequestScope();

#else
        kernel.Bind<IMailService>().To<MailService>().InRequestScope();
#endif
        kernel.Bind<SiteContext>().To<SiteContext>().InRequestScope();
        kernel.Bind<IRepository>().To<Repository>().InRequestScope();
    }
}
}
Declan
quelle
1
Die Meldung bedeutet, dass die Injektion für WebAPI nicht korrekt registriert ist. Ich vermute, dass so etwas auch für MVC5 erforderlich sein könnte.
Joachim Isaksson
@JoachimIsaksson Ich vermute dasselbe, würden Sie wissen, was ich tun muss, um dies zu registrieren?
Declan
1
@Declan ... Joachims Link sagt Ihnen, was zu tun ist. Der einzige Unterschied, den ich in CreateKernel sehe, besteht darin, dass Sie diese Zeile nicht haben: GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver (Kernel);
Jack
@Declan, ich glaube, Sie können mir bei diesem Problem helfen, wenn Sie 30 Sekunden Zeit haben ... Vielen Dank! stackoverflow.com/questions/22401403/…
Luis Gouveia

Antworten:

105

Das Ninject.Web.WebApi NuGet- Paket wurde gerade veröffentlicht. Von nun an verwendet die bevorzugte Lösung dieses Paket. Ich konnte keine zugehörige Dokumentation finden, aber nach der Installation des Pakets funktionierte alles für mich.

Install-Package Ninject.Web.WebApi 

Nach der Installation werden sowohl die normalen MVC- als auch die API-Controller-Instanzen von Ninject bereitgestellt.

Wenn Sie Ninject.Web.Common bereits installiert haben, speichern Sie Ihre Bindungen aus NinjectWebCommon.cs und lassen Sie Nuget NinjectWebCommon.cs während der Installation neu schreiben und Ihre Bindungen zurücksetzen, wenn Sie fertig sind.

Wie in den Kommentaren erwähnt, benötigen Sie abhängig von Ihrem Ausführungskontext auch eines der folgenden Pakete:

  • Ninject.Web.WebApi.WebHost
  • Ninject.Web.WebApi.OwinHost
  • Ninject.Web.WebApi.Selfhost

Das häufigste Szenario ist IIS für die Auswahl des WebHost-Pakets.

Wenn Sie eine IIS MVC5-Webanwendung von Grund auf neu starten und Ninject verwenden möchten, installieren Sie die folgenden Pakete:

  • Ninject - Ninject Core DLL
  • Ninject.Web.Common - Allgemeine Webfunktionalität für Ninject, z. InRequestScope ()
  • Ninject.MVC5 - MVC-Abhängigkeitsinjektoren, z. Controller für MVC bereitzustellen
  • Ninject.Web.Common.WebHost - Registriert die Abhängigkeitsinjektoren von Ninject.MVC5, wenn IIS die Web-App startet. Wenn Sie IIS nicht verwenden, benötigen Sie ein anderes Paket (siehe oben)
  • Ninject.Web.WebApi WebApi-Abhängigkeitsinjektoren, z. Controller für WebApi bereitzustellen
  • Ninject.web.WebApi.WebHost - Registriert die Abhängigkeitsinjektoren von Ninject.Web.WebApi, wenn IIS die Web-App startet.
Hari
quelle
50
Damit dies gut mit IIS funktioniert, musste ich Ninject.Web.WebApi.WebHost installieren. Dies lieferte WebActivatorEx und NinjectWebCommon, die für ein neues WebApi-Projekt notwendig erscheinen.
Arical
Können wir MVC-Website und WebAPI im selben Projekt verwenden?
Jitendra Pancholi
3
Dies führte bei der Installation der Pakete nicht zum Überschreiben von Dateien. Durch Hinzufügen von Ninject.Web.WebApi und Ninject.Web.WebApi.WebHost wurde das Problem in meiner kombinierten MVC + Web API-Anwendung behoben.
JMSB
3
Vergessen Sie nicht, GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel); nachRegisterServices(kernel);
Jaybro
Ab dem 13.07.2017 funktionierte diese Lösung mit WebApi2 und MVC5 bei mir nicht. Pro Snippet auf dieser Seite thisdevmind.com/2015/01/19/… . Ich habe WebApi und WebApi.WebHost gemäß Empfehlung deinstalliert, "meinen eigenen Resolver gerollt" und konnte alles zum Laufen bringen. Ich folgte dieser Anleitung: peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api
Kyle
37

Sie haben dieses Problem, weil Controller und ApiController unterschiedliche Abhängigkeitsauflöser verwenden. Die Lösung ist sehr einfach.

Erstellen Sie zunächst neue Klassen von Dependency Resolver und Dependency Scope. Sie können dies verwenden:

 public class NinjectResolver : NinjectScope, IDependencyResolver
{
    private readonly IKernel _kernel;
    public NinjectResolver(IKernel kernel)
        : base(kernel)
    {
        _kernel = kernel;
    }
    public IDependencyScope BeginScope()
    {
        return new NinjectScope(_kernel.BeginBlock());
    }
}

public class NinjectScope : IDependencyScope
{
    protected IResolutionRoot resolutionRoot;
    public NinjectScope(IResolutionRoot kernel)
    {
        resolutionRoot = kernel;
    }
    public object GetService(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).SingleOrDefault();
    }
    public IEnumerable<object> GetServices(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).ToList();
    }
    public void Dispose()
    {
        IDisposable disposable = (IDisposable)resolutionRoot;
        if (disposable != null) disposable.Dispose();
        resolutionRoot = null;
    }
}

Fügen Sie danach die nächste Zeile zur Methode CreateKernel () in NinjectWebCommon hinzu

 GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
Artur Movsesyan
quelle
1
Diese Antwort erklärt, welcher DependencyResolver verwendet werden soll und wann (im Zusammenhang mit den verwendeten Ninject-Bibliotheken) stackoverflow.com/a/22255403/280564
Tim
2
Ich empfehle dringend, das Nuget-Paket zu verwenden, das jetzt erhältlich ist. Ich hatte Probleme mit Code ähnlich wie oben
JoshBerke
1
-1, da IActivationBlock nicht die bevorzugte Methode ist und bald entfernt wird ( planetgeek.ch/2012/04/23/future-of-activation-blocks ). Bitte aktualisieren Sie Ihre Lösung. Das Problem, mit dem ich bei der Implementierung der obigen Lösung konfrontiert war, war, dass sich alle in SingletonScope registrierten Abhängigkeiten wie TransientScope verhielten. Hier ist ein weiterer Link: stackoverflow.com/questions/26708979/…
Shankbond
Bitte aktualisieren Sie Ihre Antwort mit dem Hinweis oben und ich werde -1
Shankbond
29

Ich hatte das gleiche Problem. Nach der Installation der folgenden NuGet-Pakete:

  • Ninject
  • Ninject.web.WebApi
  • Ninject.web.WebApi.WebHost
  • Ninject.MVC3
  • Ninject.web.Common
  • Ninject.web.Common.WebHost

alles funktioniert gut

Oleg
quelle
8
+1 Danke!. Ich habe "Ninject.web.WebApi.WebHost" nicht installiert, und nachdem Sie gepostet haben, habe ich es getan. Alles ist jetzt in Ordnung.
Tchaps
3
Ich musste mich auch Ninject.web.WebApi.WebHostfür die Unterstützung bedanken!
ChaseHardin
2
Ninject.web.WebApi.WebHost erstellt alle benötigten Dateien. Sie müssen nur Ihre Implementierung in die bereitgestellten RegisterServices schreiben. Die anderen Antworten sind verwirrend. Dies ist das einzige, was Sie tun müssen.
Erik Bergstedt
Dies ist die Antwort, die auch für mich funktioniert hat. Ich frage mich jedoch, warum wir all diese Pakete brauchen. Kann mich jemand auf einen Link oder ein Tutorial verweisen, das erklärt, was unter der Haube vor sich geht?
Xabush
24

Ich habe festgestellt, dass die Assembly Ninject.Web.WebApi.dll einen eigenen DependencyResolver definiert und ihn automatisch beim Kernel in der Klasse Ninject.Web.WebApi.WebApiModule registriert.

Also füge ich einfach eine Zeile zu NinjectWebCommon.CreateKernel hinzu ...

GlobalConfiguration.Configuration.DependencyResolver = 
    kernel.Get<System.Web.Http.Dependencies.IDependencyResolver>();

Schließlich hat mein Projekt folgende Abhängigkeiten:

  • Ninject 3.2.0
  • Ninject.Web.Common 3.2.0
  • Ninject.Web.WebApi 3.2.4
user1295211
quelle
1
Meine Güte, es funktioniert !!! Darüber hinaus muss die GlobalConfiguration System.Web.Http verwenden. Namespace.
Chutipong Roobklom
einfachste und beste Antwort
avidenic
funktioniert für mich, habe ich vor "RegisterServices (Kernel)" hinzugefügt; Zeile innerhalb des try {} -Blocks. Vielen Dank!
Rochasdv
Vielen Dank. Du bist toll. Ich habe ein paar Stunden verschwendet. Dies wurde im MVC-Projekt nicht benötigt, aber in der Web-API.
Manish Jain
3

Nur für andere, die vielleicht ein ähnliches Setup wie ich haben und wie ich über Google hierher gekommen sind.

Ich hatte mehrere Anwendungen mit einem WebApi-Projekt. Ich würde den obigen Fehler erhalten, wenn ich die Bindung nicht in die RegisterServices-Methode aufgenommen hätte. Überprüfen Sie also vor dem Herausziehen der Haare, ob die Bindung eingerichtet ist. Der Fehler sagt Ihnen nicht, dass Sie fehlende Bindungen haben. Was wäre, wenn sich die Anwendung im selben Projekt wie das WebApi befindet.

Richard Frankreich
quelle
2
Fehlermeldung 'Stellen Sie sicher, dass der Controller über einen parameterlosen öffentlichen Konstruktor verfügt.' ist in diesem Fall äußerst irreführend. Diese Antwort funktionierte für mich, nachdem ich stundenlang alle möglichen anderen Dinge ausprobiert hatte. Nur eine einfache fehlende Bindung!
Jedediah
2

Ich musste kürzlich Web Api 2 zum Laufen bringen, damit ich diesen Teil der Frage beantworten kann.

Dies sind die Nuget-Pakete, die für Web Api 2- benötigt werden.

Ninject
Ninject.Web.Common
Ninject.Web.Common.WebHost
Ninject.Web.WebApi 
WebActivatorEx 

Dann bearbeiten Sie NinjectWebCommon.CreateKernel(..)einschließlich

RegisterServices(kernel);
// the next line is the important one
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;

Ich habe einen ausführlicheren Beitrag dazu geschrieben - http://NoDogmaBlog.bryanhogan.net/2016/04/web-api-2-and-ninject-how-to-make-them-work-together/ einschließlich eines vollständigen Lösung zum Download.

Bryan
quelle
1

Sie sollten diese Pakete von Nuget in einem webAPI-Projekt installieren.

  1. Ninject
  2. Ninject.Web.Common
  3. Ninject.Web.Common.WebHost
  4. Ninject.Web.WebApi
  5. Ninject.Web.WebApi.WebHost

Anschließend müssen Sie das NinjectPaket auch im Repository-Projekt installieren (die Version muss mit der im API-Projekt identisch sein). Ich hatte das gleiche Problem, als für Ninject eine andere Version installiert war.

Sh.Imran
quelle
0

Ich hatte dieses Problem in einer Lösung, in der das Projekt, in dem ich Ninject verwendete, keine Web-API verwendete (ich habe bisher 6 Projekte in meiner Lösung). Ich bekam immer wieder den gefürchteten "parameterlosen Konstruktor erforderlich", was offensichtlich bedeutete, dass die Ninject-Injektion beim Hinzufügen nicht instanziiert wurde, da sie in den leeren Konstruktor fiel. Ich habe verschiedene Lösungen ausprobiert, aber am Ende habe ich meine Ninject-Pakete überprüft und festgestellt, dass das Ninject.Web.Webapi-Paket installiert wurde. Ich habe dies deinstalliert und sauber gemacht und neu aufgebaut. Dies löste das Problem. Mein anderes Projekt auf niedrigerer Ebene bezog sich auf das Ninject.Web.Api-Paket, und dummerweise hatte ich das in mein Web-Front-End-Projekt installiert.

Ich hoffe, dies kann anderen Leuten helfen, die alle Stack-Lösungen ausprobiert haben und keine Ahnung haben.

Mike Cave
quelle