2013-01-15 10 views
12

Ho utilizzato l'estensione NuGet Ninject MVC3 e non sono riuscito a farlo inoculare su un controller su richiesta. Non sembra essersi associato, dato che MVC sta cercando il costruttore paramaterless. Ecco l'analisi dello stack:Ninject + MVC3 non si sta iniettando nel controller

[MissingMethodException: No parameterless constructor defined for this object.] 
     System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0 
     System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache) +98 
     System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache) +241 
     System.Activator.CreateInstance(Type type, Boolean nonPublic) +69 
     System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +67 

    [InvalidOperationException: An error occurred when trying to create a controller of type 'MyApp.Presentation.Controllers.SearchController'. Make sure that the controller has a parameterless public constructor.] 
     System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +182 
     System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +80 
     System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +74 
     System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +199 
     System.Web.Mvc.<>c__DisplayClass6.<BeginProcessRequest>b__2() +49 
     System.Web.Mvc.<>c__DisplayClassb`1.<ProcessInApplicationTrust>b__a() +13 
     System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7 
     System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22 
     System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Func`1 func) +124 
     System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +98 
     System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +50 
     System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16 
     System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8862676 
     System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184 

E il controllore che sto cercando di iniettare in (ci vuole una classe di base al momento):

public class SearchController : MainBaseController 
{ 

    private readonly MyApp.Domain.Tutor.TutorSearch TutorSearch; 
    protected static readonly log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

    [Ninject.Inject] 
    public SearchController(MyApp.Domain.Tutor.TutorSearch tutorSearch) 
    { 
     this.TutorSearch = tutorSearch; 
    } 

    .... (no other constructors) 
} 

E la parte rilevante delle mie NinjectWebCommon.cs:

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) 
    { 
     INinjectModule[] modules = new INinjectModule[] 
     { 
      new Domain.DomainModule() 
     }; 

     kernel.Load(Assembly.GetExecutingAssembly()); 
     kernel.Load(modules); 

     kernel.Bind<MyApp.Domain.Tutor.TutorSearch>().ToSelf(); 

     // *************** 
     var t = kernel.Get<MyApp.Presentation.Controllers.SearchController>(); 
    } 

Infine, qui è DomainModule:

public class DomainModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<Data.Profile.IProfileProvider>().To<Data.Profile.XmlProfileProvider>(); 
     Bind<Data.Subject.ISubjectProvider>().To<Data.Subject.XmlSubjectProvider>(); 
    } 
} 

Come si può vedere nel mio NinjectWebCommon.cs nella riga contrassegnata da asterischi, ho provato a costruire il controller esplicitamente come test. Funziona perfettamente, con gli Xml..Providers correttamente iniettati.

C'è qualcosa che ho perso? Non ne so abbastanza su cosa succede sotto l'estensione NuGet MVC3 e quindi non ho idea di che punto i binding del controller stiano fallendo.

Qualsiasi suggerimento su cosa guardare sarebbe molto apprezzato, grazie.

+0

Traw, c'è un motivo particolare che si sta utilizzando implementazioni concrete piuttosto che Interfacce. ?? Ho aggiunto uno schizzo veloce di come dovrebbe apparire –

risposta

17

Così, dopo un bel po 'di bricolage disperata, ho finalmente trovato il mio problema. Stavo fa riferimento alla DLL MVC4 (System.Web.Mvc) e non aveva reindirizzato il legame di vecchia versione 3.0.0.0 alla 4.0.0.0:

<dependentAssembly> 
    <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" /> 
    <bindingRedirect oldVersion="1.0.0.0" newVersion="4.0.0.0" /> 
    <bindingRedirect oldVersion="2.0.0.0" newVersion="4.0.0.0" /> 
    <!-- The following line was missing --> 
    <bindingRedirect oldVersion="3.0.0.0" newVersion="4.0.0.0" /> 
    </dependentAssembly> 

Almeno, spero che sia una soluzione decente.

Edit: come suggerito qui di seguito, la seguente riga è più succinta:

<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" /> 
+0

questo mi ha aiutato a risolvere un problema simile che stavo avendo [qui ...] (http://stackoverflow.com/questions/18723935) – melkisadek

+7

Non sarebbe 'bindingRedirect oldVersion = "0.0.0.0-4.0.0.0" newVersion = "4.0.0.0" 'copre questi tre casi in una riga? – neontapir

+0

Dove posso trovare questo file? Sto avendo lo stesso problema. – Doug

1

Traw, c'è una ragione particolare per cui si stanno utilizzando le implementazioni concrete piuttosto che le interfacce. ?? Allo stato attuale, stai ottenendo un vantaggio pari a zero nel corso della lezione (e sono sorpreso che tu stia ottenendo qualsiasi cosa per lavorare) vorrei refactoring e mettere tutto dietro un'interfaccia, quindi legare l'interfaccia all'implementazione concreta .

Ecco un rapido colpo a come potrebbe sembrare:

// 'imagined' ISearchType interface 
public interface ISearchType 
{ 
    int Id { get; set; } 
    string LastName { get; set; } 
} 

// 'imagined' TutorSearch concrete class 
public class TutorSearch : ISearchType 
{ 
    public int Id { get; set; } 
    public string LastName { get; set; } 
} 

// your revised controller code 
private readonly ISearchType _tutorSearch; 
public SearchController(ISearchType searchType) 
{ 
    _tutorSearch = searchType; 
} 

quindi, nella vostra registrazione dei servizi (Ninject), dovreste aggiungere:

kernel.Bind<ISearchType>().To<TutorSearch>(); 

Questo dovrebbe farti un poco oltre. Inoltre, var t = kernel.Get<...> in realtà non fa nulla - nel caso ti stavi chiedendo cosa fosse successo a "esso".

Buon divertimento ...

+0

Ciao Jim. Innanzitutto, grazie per la tua risposta. La ragione per cui sto usando l'implementazione concreta è perché in questa fase non sono riuscito a comprenderlo, e la classe in questione ha le dipendenze che vorrei iniettare. Avevo l'impressione che a Ninject sarebbe andata bene iniettando un'implementazione concreta o non è così? La riga con 'var t = kernel.Get <...>' era semplicemente un test da testare nel mio debugger, e ha funzionato bene - Ninject ha costruito il controller perfettamente. Semplicemente non su richiesta web. Ho anche provato a passare un'interfaccia e ho ottenuto lo stesso risultato! – Traw

+0

Ciao Traw - contento che tu abbia tutto funzionato come speravo. tuttavia, scoraggerei l'iniezione di lezioni concrete via ninject (anche se è possibile). quale vantaggio ottieni ?? si dovrebbe anche solo creare la classe nel costruttore vuoto in quanto non cambierà mai l'implementazione. il mio consiglio sarebbe iniziare con interfacce e codificare le tue implementazioni concrete contro quelle. questa sarebbe la migliore pratica in quanto, in quel momento, si dovrà solo rifattorizzare il codice nelle classi concrete. inoltre, per il test delle unità, non è possibile eseguire alcuna operazione in base all'esempio di codice che hai fornito. –

+0

anche !! un altro vantaggio della codifica rispetto a un'interfaccia è il fatto che è possibile coltivare il lavoro ad altri sviluppatori e sapere che le implementazioni saranno iniettabili in funzionalità esistenti. se porti via qualcosa da questa discussione, ti prego, promettimi che ricomincerai da capo e lavorerai dalle interfacce - per favore, ti prego carina per favore :) buona fortuna .. –

5

Utilizzando Visual Studio e Nuget è necessario eseguire questo comando

Installare-Pacchetto Ninject.MVC3

(sostituire il 3 a seconda della versione MVC è in esecuzione)

Questo risolverà il vostro problema

+0

Questo più o meno ha funzionato per me. Pensavo di aver installato Ninject.MVC5 (Ninject.Web.Mvc) ma non lo era. Ho appena avuto Ninject e Ninject.Web.Common per qualche motivo. – Marnee

Problemi correlati