5

Sono consapevole che sono state poste mille domande su questo argomento, ma ne ho attraversate almeno una dozzina e ancora non riesco a collegare i punti. Sto cercando di configurare l'iniezione di dipendenza per contesti di entità.Ninject: Contesto entità per controller

ho sempre creato mio contesto entità come ho visto nel tutorial MS, in questo modo:

public class UserController : Controller 
{ 
    private DbEntities db = new DbEntities(); 

} 

lettura recente mi ha detto che questo non è più (se mai lo è stato) la migliore pratica, e dovrebbe essere usato un metodo di iniezione dipendente. Ninject è menzionato spesso, ma sto vedendo come ti muovi da quello che ho, all'esempio dai Ninject documentation.

Dovrebbe assomigliare a questo quando ho finito, giusto?

La documentazione inizia con "Nel passaggio precedente abbiamo già preparato tutto ciò che è necessario per l'iniezione del controller". che è fonte di confusione, dal momento che il passaggio precedente era l'installazione. Ho usato il metodo Nuget per l'installazione, ma non so cosa significhi quando dice "Ora carica i tuoi moduli o definisci i bind nel metodo RegisterServices." Come faccio a farlo ed è un'entità un modulo o un'associazione? La documentazione sembra così scarsa.

Mi dispiace se ho saltato qualcosa di critico nei documenti, sono rimbalzato tra i forum per ore cercando di capire questo passo.

risposta

4

ho usato il metodo Nuget da installare, ma non so che cosa significa quando si dice "Ora caricare i moduli o definire attacchi nel metodo RegisterServices." Come faccio a farlo, ed è un'entità un modulo o un'associazione?

L'installazione di Nuget in realtà fa già un sacco di cose per voi. La cosa più importante è che imposta Ninject come controller factory, il che significa che Ninject creerà i tuoi controller ed è in grado di passare tutte le dipendenze che hai registrato con esso.

Se si controlla la cartella App_Start si troverà un file NinjectMVC3.cs. C'è già un metodo vuoto RegisterServices() che puoi usare per registrare le tue dipendenze.

Per il tuo esempio devi essere in grado di risolvere DbEntities. Il modo più semplice più semplice per farlo è:

kernel.Bind<DbEntities>().ToSelf(); 

Detto questo si dovrebbe passare a un'interfaccia per il controller in modo che il controllo non dipende da Entity Framework, utilizzando le astrazioni e la registrazione di una classe concreta da utilizzare nel Il contenitore di IoC è uno dei motivi principali dell'iniezione di dipendenza.

Questo dovrebbe dare un inizio - la documentazione che si collega a sembra un po 'obsoleta. Consiglierei di guardare lo Ninject MVC3 sample su github.

+0

Grazie. Ho scaricato il campione, ma ci sono così tante cose che è difficile dire cosa sta facendo cosa.Non capisco come Bind funzioni ancora, ma quella linea sembra essere tutto ciò che serve per dare al costruttore del controllore il contesto. Puoi consigliare articoli o tutorial che spieghino in effetti che cosa sta succedendo qui? – Tyrsius

+0

Vorrei controllare i collegamenti su 'http: // ninject.org/learn', anche in generale per l'iniezione di dipendenza dai un'occhiata al libro" Dipendenza da iniezione in .NET "di Mark Seemann – BrokenGlass

1

L'iniezione di dipendenza può sembrare inizialmente confusa, ma in realtà è piuttosto semplice.

Un "contenitore" di Iniezione di dipendenza è fondamentalmente una fabbrica generica con varie funzioni di gestione della durata dell'oggetto. In particolare, Ninject utilizza la sintassi kernel.Bind() per confgurare questa fabbrica.Quando dici kernel.Bind<DbEntities>().ToSelf() questo significa che Ninject creerà un'istanza del tipo associato (DbEntities in questo caso) ogni volta che quel tipo viene richiesto. Questa richiesta è in genere la seguente:

var entities = kernel.Get<DbEntities>(); // Note: don't do this, just an example 

Al suo centro, questo è ciò che è Dipendenza Iniezione. Una fabbrica generica in grado di istanziare tipi arbitrari.

Tuttavia, c'è molto di più. Una buona caratteristica di Dependency Injection è che istanzia anche qualsiasi tipo dipendente nel processo. Quindi, supponiamo di avere un controller e quel controller ha una dipendenza da DbEntities. Bene, quando un controller viene istanziato dal framework DI, creerà anche un'istanza delle DbEntities dipendenti. Guarda il codice qui sotto. Quando il MyController viene istanziato, i DbEntities otterrà automaticamente un'istanza (ammesso che abbiate legato alla classe DbEntities di auto nella configurazione DI)

var controller = kernel.Get<MyController>(); 

public class MyController : Controller { 
    private DbEntities _entities; 
    public MyController(DbEntities entities) { 
     _entities = entities; 
    } 
} 

Questo è ricorsiva. Qualsiasi classe che viene istanziata e che ha oggetti da cui dipenderà può anche essere istanziata, e così via, e così via fino a che, finalmente, tutto ha ciò di cui ha bisogno per fare il suo lavoro.

Ora, la cosa bella di MVC è che ha un modo integrato per utilizzare automaticamente qualsiasi contenitore DI. Non è necessario chiamare lo kernel.Get perché il framework lo fa per te quando crea i controller quando arriva una richiesta. Questa funzione è chiamata IDependencyResolver ed è un'interfaccia che il framework MVC utilizza per consentire l'utilizzo di contenitori DI di terze parti dal quadro. sezione

Se si installa Ninject utilizzando il pacchetto Nuget Ninject.MVC3 allora configurerà automaticamente tutto questo per voi, ed è necessario solo aggiungere le associazioni ai RegisterServices() di NinjectMVC3.cs

C'è un sacco più di questo, ma questo dovrebbe darti una comprensione di base. L'Iniezione delle Dipendenze ti permette di dimenticare i dettagli della gestione degli oggetti creati e distrutti, devi solo specificare nel tuo costruttore quali dipendenze hai bisogno e supponendo che tu abbia dei collegamenti per loro nella tua configurazione, MVC si prenderà cura di crearli e distruggerli per tu. Li usi e basta.

EDIT:

Per essere chiari, non mi consiglia di utilizzare gli esempi dò sopra. Sono solo semplici illustrazioni di come funziona DI. In particolare, la sintassi Get() è nota come "Posizione del servizio" ed è considerata non valida. Tuttavia, in definitiva un codice, da qualche parte deve chiamare Get(), è solo sepolto nel profondo del framework.

Come afferma Adam, il collegamento diretto al contesto delle entità di dati non è una grande idea e alla fine dovresti passare a utilizzare un approccio basato sull'interfaccia.

+0

che lega un controller a dati concreti accedere all'implementazione mentre si utilizza l'iniezione di dipendenza? –

+0

@AdamTuliper: sono esempi semplificati di ciò che accade nel framework. Idealmente si userebbero interfacce, ma non volevo aumentare la complessità dell'esempio. Il framework stesso istanzia il controller, ma usa il contenitore DI configurato per risolvere i tipi iniettati, quindi è come se il controllore stesso fosse vincolato. –

+0

@MyerstereMan, grazie, questo è stato molto istruttivo. Per chiarire: poiché l'implementazione di Ninject di MVC3 imposta il 'IDependencyResolver' per te,' .Get() 'non è mai necessario? Quindi '.Get()' può essere usato in framework desktop? – Tyrsius

0

Non inserirei mai un tipo concreto qui: si sta direttamente accoppiando a un'implementazione di accesso ai dati.

Associare invece a IDbContext (o IUnitOfWork) - queste sono interfacce definite con un'implementazione concreta di backup di DbContext, in questo modo è possibile astrarre facilmente la tecnologia che si sta utilizzando, rendendola più scambiabile, verificabile, manutenibile, ecc.

es: http://blogs.planetcloud.co.uk/mygreatdiscovery/post/EF-Code-First-Common-Practices.aspx#disqus_thread

+0

Sono d'accordo in linea di principio, ma legarsi a un tipo concreto è un buon modo per apprendere le basi della DI senza dover anche approfondire le implementazioni dell'interfaccia. –

+0

@AdamTuliper Dovrò leggere più avanti questo articolo, ma questa soluzione richiede molto più lavoro. Non capisco come potrei chiamare specifici set di entità (tabelle sql) sul mio contesto dal controller senza l'accoppiamento con un'implementazione specifica. – Tyrsius