2010-03-11 4 views
30
mit

Vor kurzem habe ich Ninject Version 2.0 eingeschaltet und begann die folgende Störung zu erhalten:Fehler „Mehr als eine passende Bindung zur Verfügung stehen“, wenn Ninject.Web.Mvc 2.0 und ASP.NET MVC 1.0

 
Error occured: Error activating SomeController 
More than one matching bindings are available. 
Activation path: 
    1) Request for SomeController 

Suggestions: 
    1) Ensure that you have defined a binding for SomeController only once. 

Ich bin jedoch nicht in der Lage, bestimmte Wiedergabewege zu finden. Manchmal kommt es vor, manchmal nicht. Ich benutze NinjectHttpApplication für automatische Steuerungen Injektion. Controller sind in einer separaten Baugruppe definiert:

public class App : NinjectHttpApplication 
{ 
    protected override IKernel CreateKernel() 
    { 
     INinjectModule[] modules = new INinjectModule[] { 
      new MiscModule(), 
      new ProvidersModule(), 
      new RepositoryModule(), 
      new ServiceModule() 
     }; 

     return new StandardKernel(modules); 
    } 

    protected override void OnApplicationStarted() 
    { 
     RegisterRoutes(RouteTable.Routes); 
     RegisterAllControllersIn("Sample.Mvc"); 
     base.OnApplicationStarted(); 
    } 

    /* ............. */ 

} 

Vielleicht ist jemand mit diesem Fehler vertraut.

Irgendwelche Ratschläge?

+0

FYI, es ist nicht exklusiv für ASP.NET MVC 1.0. Ich hatte es gerade in ASP.NET MVC 2.0 passiert. – mckamey

+2

Ich habe ein Repro-Projekt für diese Situation erstellt und in die Ninject-dev-Gruppe hochgeladen. Hoffentlich erkennt jemand das Problem. Ich war nicht in der Lage, eine einfache Lösung zu sehen. http://groups.google.com/group/ninject-dev/files – mckamey

+0

FYI, ich habe überprüft, dass dies für mich in Version 2.1.0.0 von NinjectNinject.Web.Mvc (MVC2) behoben ist. In der neuesten Version müssen Sie nicht mehr RegisterAllControllersIn (...) aufrufen. – mckamey

Antwort

23

Ich habe dieses Problem vor kurzem herausgefunden. Offensichtlich führt die NinjectHttpApplication.RegisterAllControllersIn() - Funktion nicht alle erforderlichen richtigen Bindungen aus. Es bindet Ihre konkreten Controller-Implementierungen an IController-Anforderungen. Zum Beispiel, wenn Sie eine Controller-Klasse namens SampleMvcController haben, die von System.Web.Mvc.Controller erbt. Es täte die nachfolgend genannte Bindung während der Anwendung Start:

kernel.Bind<IController>().To(SampleMvcController).InTransientScope().Named("SampleMvc"); 

Aber wenn die NinjectControllerFactory debuggen, finde ich diesen Antrag für die Ninject Kernel gemacht werden, ein Objekt für die Klasse „SampleMvcController“, nicht für ein konkreten zurückzukehren Implementierung von IController unter Verwendung der genannten Bindung von "SampleMvc".

Aus diesem Grund erstellt die erste Webanforderung, die den SampleMvcController beteiligt ist, eine Bindung von SampleMvcController an sich. Dies ist jedoch nicht threadsicher. Wenn also mehrere Webanfragen gleichzeitig ausgeführt werden, können die Bindungen möglicherweise mehr als einmal auftreten. Dieser Fehler tritt nun auf, wenn mehrere Bindungen für den SampleMvcController vorhanden sind.

Sie können dies überprüfen, indem Sie eine MVC-URL schnell aktualisieren, nachdem die Webanwendung neu gestartet wurde.

Das Update:

Der einfachste Weg, um dieses Problem zu beheben, ist eine neue NinjectModule für Ihre Controller Bindung zu schaffen, und dieses Modul während der Anwendung Starts zu laden. In diesem Modul binden Sie selbst jede Ihrer definierten Steuerungen, etwa so:

class ControllerModule : StandardModule { 
     public override Load() { 
     Bind<SampleMvcController>().ToSelf(); 
     Bind<AnotherMvcController>().ToSelf(); 
     } 
    } 

Aber wenn Sie nichts dagegen haben die Ninject Quellcode ändern, können Sie die RegisterAllControllersIn() Funktion zur Selbst binden jeden Controller modifizieren treffen.

+1

Danke für den Hinweis. Ich werde es versuchen und deine Antwort markieren. Hast du schon Nate Kohari benachrichtigt? =) –

+0

Dank dafür haben wir uns mit diesem Problem die Haare ausgezogen. – DavidWhitney

1

Sind Sie sicher, dass Sie wirklich jedes Mal ein ganz neues Kernel von Grund auf in Ihrem OnApplicationStarted erstellen, wenn es aufgerufen wird? Wenn Sie es nicht sind und Sie es tatsächlich einmal erstellen, führen Sie das Registrierungsbit möglicherweise zweimal aus. Denken Sie daran, dass nicht garantiert ist, dass innerhalb einer bestimmten Anwendungsdomäne immer nur eine App Klasse instanziiert wird.

+0

Schauen Sie sich README am Ende der Seite http://github.com/enkari/ninject.web.mvc an (ich denke, dass mein Code ziemlich ähnlich ist). Wenn ich jedoch die NinjectHttpApplication Application_Start() -Methode http://github.com/enkari/ninject.web.mvc/blob/master/mvc1/src/Ninject.Web.Mvc/NinjectHttpApplication.cs anschaue, denke ich an diese Konfiguration wird für einzelne Kernel-Instanzen ausgeführt. –

+0

@Cray: Ich werde in der Zeit suchen - Entschuldigung, habe jetzt keine Zeit, aber wollte antworten, falls es dich entsperrt hat. Der Hauptpunkt meines Posts ist zu sagen: "Diese Ausnahme legt nahe, dass Sie einen Duplikatsatz oder Bindings irgendwie in den Kernel einfügen, vielleicht durch zweimaliges Initialisieren in denselben Kernel", egal wo Sie den Code bekommen haben und unabhängig davon, ob Ihre Frage steht eine genaue Wiedergabe Ihres tatsächlichen Codes, der fehlschlägt. (Ich habe Null mit dem RTM NI2 getan, aber viele mit verschiedenen Pre-2-Builds) –

0

Ich habe diese auf meine global.ascx.cs Datei:

 public void RegisterAllControllersInFix(Assembly assembly) 
    { 
     RegisterAllControllersInFix(assembly, GetControllerName); 
    } 

    public void RegisterAllControllersInFix(Assembly assembly, Func<Type, string> namingConvention) 
    { 
     foreach (Type type in assembly.GetExportedTypes().Where(IsController)) 
      Kernel.Bind(type).ToSelf(); 
    } 

    private static bool IsController(Type type) 
    { 
     return typeof(IController).IsAssignableFrom(type) && type.IsPublic && !type.IsAbstract && !type.IsInterface; 
    } 

    private static string GetControllerName(Type type) 
    { 
     string name = type.Name.ToLowerInvariant(); 

     if (name.EndsWith("controller")) 
      name = name.Substring(0, name.IndexOf("controller")); 

     return name; 
    } 

Da rief es von meinem OnApplicationStarted (Methode) wie folgt:

 RegisterAllControllersIn(Assembly.GetExecutingAssembly()); 
     RegisterAllControllersInFix(Assembly.GetExecutingAssembly()); 

schwierig zu wissen, ob diese es fest, obwohl weil es so intermittierend ist.

+0

Probieren Sie etwas wie WebClient.DownloadString ("http: // yoursite /") in Schleife, ... in mehreren Threads =) –

+0

Wird tun - danke Denis – coalvilledave

16

Ich habe mich seit Monaten mit diesem Problem beschäftigt. Ich habe so viele Möglichkeiten ausprobiert, konnte aber nicht zu einer Lösung kommen. Ich wusste, dass es ein Threading-Problem war, weil es nur auftreten würde, wenn meine Site stark ausgelastet war. Erst kürzlich wurde ein Fehler im Ninject-Quellcode gemeldet und behoben, der dieses Problem löst.

Hier ist ein Verweis auf die issue. Es wurde in Build 2.1.0.70 der Ninject-Quelle behoben. Die Schlüsseländerung war in KernelBase.cs durch die Linie zu entfernen

context.Plan = planner.GetPlan(service); 

und es mit

lock (planner) 
{ 
    context.Plan = planner.GetPlan(service); 
} 

Zur Nutzung dieser neuen Build mit MVC ersetzen Sie die neueste Version von Ninject dann die neueste Version erhalten erhalten müssen von ninject.web.mvc. Erstelle ninject.web.mvc mit dem neuen Ninject-Build.

Ich benutze diesen neuen Build seit ungefähr einer Woche mit einer schweren Last und ohne Probleme. Das ist die längste Zeit, die es ohne Probleme gegangen ist, also würde ich dies als eine Lösung betrachten.

+0

Awesome! Das sind große Neuigkeiten. Ich habe mich selbst damit beschäftigt. Danke, dass du diese Antwort gegeben hast, Steve! –

1

Meine Antwort war ein bisschen offensichtlicher.

Ich hatte die Bindung für einen meiner Controller mehr als einmal während Refactor meines Codes erklärt.

Verwandte Themen