ich habe mein Projekt mit Ninject IoC
.
Mein Projekt hat regelmäßige Asp.Net MVC
Controller und Web Api
Steuerungen. Jetzt arbeitet Ninject
mit Web Api
aber Ninject
funktioniert nicht mit regulären Asp.MVC
Steuerungen.
Meine regulärer MVC-Controller Implementierung;
public class GalleryController : BaseController
{
public GalleryController(IUow uow)
{
Uow = uow;
}
........
}
Fehler bei der Verwendung mit regulären Controller
An error occurred when trying to create a controller of type 'Web.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]
Wenn ich jedoch den gleichen Code mit Web Api, versuche, funktioniert es
public class GalleryController : BaseApiController
{
public GalleryController(IUow uow)
{
Uow = uow;
}
......
}
meine Schnittstelle, die Differenz-Repositorys enthält (das Factory-Muster)
public interface IUow
{
// Save pending changes to the data store.
void Commit();
//Repositoryries
IRepository<Gallery> Gallery { get; }
IMenuRepository Menus { get; }
}
NinjectDependencyScope
class;
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
var 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<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
NinjectDependencyResolver
class;
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());
}
}
Ninject
Konfiguration für Global.asax;
public class IocConfig
{
public static void RegisterIoc(HttpConfiguration config)
{
var kernel = new StandardKernel(); // Ninject IoC
//kernel.Load(Assembly.GetExecutingAssembly()); //only required for asp.net mvc (not for webapi)
// These registrations are "per instance request".
// See http://blog.bobcravens.com/2010/03/ninject-life-cycle-management-or-scoping/
kernel.Bind<RepositoryFactories>().To<RepositoryFactories>()
.InSingletonScope();
kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
kernel.Bind<IUow>().To<Uow>();
// Tell WebApi how to use our Ninject IoC
config.DependencyResolver = new NinjectDependencyResolver(kernel);
}
}
Global.asax
protected void Application_Start()
{
// Tell WebApi to use our custom Ioc (Ninject)
IocConfig.RegisterIoc(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfig.CustomizeConfig(GlobalConfiguration.Configuration);
AreaRegistration.RegisterAllAreas();
}
Nachdem wir viel gesucht haben, stellt sich heraus, dass wir Ninject nicht mit Web-API und regulärem MVC verwenden können. Ich meine, wir müssen die Repositories separat konfigurieren.
Ich habe dann einen netten Artikel gefunden, in dem erklärt wird, wie Sie Ninject mit asp.net mvc & web api verwenden können: http://www.codeproject.com/Articles/412383/Dependency-Injection-in-asp-net- mvc4-and-webapi-us
Und jetzt verstehe ich den Fehler nicht und es funktioniert: D
Update 1:
Versuchen Sie auch Folgendes: Schreiben einer einfachen Implementierung der Abhängigkeitsinjektion in die MVC 4-Web-API mit .NET Framework 4.5
Ich habe einige Listen geschrieben, um Ninject mit MVC und Web Api zu konfigurieren. Fügen Sie einfach die Datei (en) hinzu:
Um Bindungen für konkrete Typen hinzuzufügen, fügen Sie diese einfach in die Load()
-Methode des MainModule ein. Sie können so viele Module erstellen, wie Sie möchten, um die Bindungen zu organisieren. Sie müssen sie jedoch auch dem Array hinzufügen, das in der Eigenschaft Modules
zurückgegeben wird.
Fügen Sie dann der Application_Start()
-Methode hinzu
NinjectContainer.RegisterModules(NinjectModules.Modules)
(für MVC)NinjectHttpContainer.RegisterModules(NinjectHttpModules.Modules)
(für WebApi)Beachten Sie, dass Sie für die MVC- und die WebApi-Registrierung dasselbe NinjectModules.Modules
Verwenden können. Ich habe es nur aus Gründen der Klarheit getrennt
[~ # ~] Update [~ # ~] : Denken Sie daran, NinjectWebCommon.cs aus Ihrem Projekt zu entfernen, wenn ein neuer Kernel zur Laufzeit geladen und gebootet wird ist leider nur für mvc.
[~ # ~] Update [~ # ~] : Sie können auch verwenden
NinjectContainer.RegisterAssembly()
(für MVC)NinjectHttpContainer.RegisterAssembly()
(für WebApi)Dadurch wird Ihre aktuelle Baugruppe nach allen Modulen durchsucht. Auf diese Weise können Sie Ihre Module an einer beliebigen Stelle in Ihrem Projekt platzieren und es wird registriert
Mit MVC 5 und Web API 2.2 habe ich dieses Problem behoben, indem ich sichergestellt habe, dass die folgenden NuGet-Pakete enthalten sind:
Ninject.MVC5
Ninject.Web.WebApi.WebHost
für die Web-APIDadurch wurden andere Ninject-Abhängigkeiten installiert und ich konnte RegisterServices
bis NinjectWebCommon.cs
.
Hier ist die einfache Lösung, die für mich gut funktioniert:
Führen Sie in der Package Manager-Konsole nacheinander Folgendes aus:
Installationspaket Ninject
Installationspaket Ninject.MVC5
Fügen Sie NinjectDependencyResolver.cs zum IoC-Ordner hinzu:
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Dependencies;
namespace DemoApp.IoC
{
public class NinjectDependencyResolver : IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
public void Dispose() { } //it is not necessary to implement any dispose logic here
}
}
Nehmen Sie die folgenden Änderungen in App_Start/NinjectWebCommon.cs vor:
Fügen Sie diese Zeilen in die CreateKernel-Methode ein:
NinjectDependencyResolver ninjectResolver = new NinjectDependencyResolver (Kernel); DependencyResolver.SetResolver (ninjectResolver); // MVC GlobalConfiguration.Configuration.DependencyResolver = ninjectResolver; // Web API
Fügen Sie Ihre Bindungen in der RegisterServices-Methode wie folgt hinzu:
kernel.Bind <IHelloService> (). To <HelloService> ();
Jetzt sollte NinjectWebCommon.cs so aussehen:
[Assembly: WebActivatorEx.PreApplicationStartMethod(typeof(DemoApp.App_Start.NinjectWebCommon), "Start")]
[Assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(DemoApp.App_Start.NinjectWebCommon), "Stop")]
namespace DemoApp.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using DemoApp.IoC;
using System.Web.Mvc;
using System.Web.Http;
using DemoApp.Config;
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);
NinjectDependencyResolver ninjectResolver = new NinjectDependencyResolver(kernel);
DependencyResolver.SetResolver(ninjectResolver); //MVC
GlobalConfiguration.Configuration.DependencyResolver = ninjectResolver; //Web API
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<IHelloService>().To<HelloService>();
}
}
}
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DemoApp.Config;
namespace DemoApp.Controllers
{
public class HomeController : Controller
{
private IHelloService helloService;
public HomeController(IHelloService helloService)
{
this.helloService = helloService;
}
// GET: /Home/
public string Index()
{
return "home/index: " + helloService.GetMessage();
}
}
}
UserController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using DemoApp.Config;
namespace DemoApp.Controllers
{
public class UserController : ApiController
{
private IHelloService helloService;
public UserController(IHelloService helloService)
{
this.helloService = helloService;
}
[HttpGet]
public string Data()
{
return "api/user/data: " + helloService.GetMessage();
}
}
}
IHelloService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace DemoApp.Config
{
public interface IHelloService
{
string GetMessage();
}
}
HelloService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace DemoApp.Config
{
public class HelloService : IHelloService
{
public string GetMessage()
{
return "Hi";
}
}
}
Die endgültige Struktur sollte wie folgt aussehen:
Führen Sie nun einige Tests im Browser durch. Für mich war es:
Und das ist es.
Ich denke, das Problem ist, dass Sie keine ControllerFactory registrieren, die Ninject verwendet, um die Controller zu erstellen (und ihre Abhängigkeiten aufzulösen). Haben Sie bereits versucht, Ihre eigene ControllerFactory zu implementieren? Siehe auch hier http://bubblogging.wordpress.com/2012/06/04/mvc-controller-factory-ninject/ .
Hierfür gibt es eine elegantere Lösung von Nenad - ich habe 3 zusätzliche Stunden gebraucht, weil ich zuerst versucht habe, die Lösungen zu implementieren, die mit der vorhandenen Infrastruktur in Konflikt stehen. Es ist als Antwort auf eine andere Stapelüberlauf-Frage . Ich kopiere diese Antwort hier, nur für den Fall, dass es anderen hilft, meine verlorene Zeit zu sparen.
Es gibt eine Möglichkeit, denselben Container für MVC und die ASP.NET-Web-API freizugeben. Sie müssen nur beide Schnittstellen implementieren.
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(this.kernel.BeginBlock());
}
}
In diesem Artikel finden Sie eine Lösung: Einfache Methode zum Freigeben von Abhängigkeitsauflösern zwischen MVC und Web-API