9

Sono nuovo nel repository e in DI e sto provando a implementarlo nel mio progetto MVC 5.Utilizzo dell'invio delle dipendenze senza alcuna libreria DI

ho implementato iniezione Constructor dove nel mio controller ha un costruttore come questo:

IBook _ibook; 
public Test(IBook ibook) 
{ 
    _ibook = ibook; 
} 

Senza alcuna biblioteca DI, si genera un errore: Non v'è alcun costruttore vuoto.

Per evitare questo, ho aggiunto un altro costruttore come di seguito:

public Test():this(new Book()) 
{  
} 

Dato che io sono nuovo a DI, io non voglio rischiare la mia progetto utilizzando biblioteca DI che possono poi gettare un po 'di errore che Potrei non essere in grado di risolvere.

Desidero sapere quali problemi potrei incontrare se non utilizzo la libreria DI.

Nel caso sia consigliabile, quale libreria DI è adatta ai principianti? Ho visto alcuni video di NInject e Unity.

+4

Consiglierei SimpleInjector in quanto convalida la configurazione prima dell'avvio. Pochissimi contenitori lo fanno. Quindi qualsiasi problema in genere dovrebbe essere trovato e risolto all'inizio. – jgauffin

+0

Se a un certo punto si sta pianificando l'upgrade del progetto a ASP.NET vNext, vale la pena menzionare che includerà alcune implementazioni di base del contenitore DI che possono soddisfare le proprie esigenze (http://blogs.msdn.com/b /webdev/archive/2014/06/17/dependency-injection-in-asp-net-vnext.aspx) –

+1

Penso che sarebbe molto meglio iniziare con DI puro invece di utilizzare DI di ASP.NET vNext integrato biblioteca. [La libreria DI incorporata è inutile quando si scrivono applicazioni SOLID] (https://stackoverflow.com/a/30682214/264697). – Steven

risposta

16

È una buona idea ritardare qualsiasi decisione di utilizzare qualche tipo di strumento o libreria fino al the last responsible moment. Con un buon design è possibile aggiungere una libreria DI in seguito. Ciò significa che ti alleni con lo Pure DI.

Il punto di intercettazione preferito in MVC è l'astrazione IControllerFactory poiché consente di intercettare la creazione di controller MVC, impedendo così di dover implementare un secondo costruttore (che è is an anti-pattern). Anche se è possibile utilizzare IDependencyResolver, l'uso di tale astrazione è molto meno conveniente perché è anche chiamato da MVC per risolvere le cose che non sono in genere interessati a.

Una consuetudine IControllerFactory che fungerà da vostro composition root possono essere implementate come segue:

public sealed class CompositionRoot : DefaultControllerFactory 
{ 
    private static string connectionString = 
     ConfigurationManager.ConnectionStrings["app"].ConnectionString; 
    private static Func<BooksContext> bookContextProvider = GetCurrentBooksContext; 
    private static IBookRepository bookRepo = new BookRepository(bookContextProvider); 
    private static IOrderBookHandler orderBookHandler = new OrderBookHandler(bookRepo); 

    protected override IController GetControllerInstance(RequestContext _, Type type) { 
     // Unfortunately, because of MVC's design, controllers are not stateless, and 
     // you will have to create them per request. 

     if (type == typeof(OrderBookController)) 
      return new HomeController(orderBookHandler); 

     if (type == typeof(BooksController)) 
      return new BooksController(bookRepo); 

     // [other controllers here] 

     return base.GetControllerInstance(_, type); 
    } 

    private static BooksContext GetCurrentBooksContext() { 
     return GetRequestItem<BooksContext>(() => new BooksContext(connectionString)); 
    } 

    private static T GetRequestItem<T>(Func<T> valueFactory) where T : class { 
     var context = HttpContext.Current; 
     if (context == null) throw new InvalidOperationException("No web request."); 
     var val = (T)context.Items[typeof(T).Name]; 
     if (val == null) context.Items[typeof(T).Name] = val = valueFactory(); 
     return val; 
    } 
} 

Il nuovo controller fabbrica può essere agganciato in MVC come segue:

public class MvcApplication : System.Web.HttpApplication 
{ 
    protected void Application_Start() { 
     ControllerBuilder.Current.SetControllerFactory(new CompositionRoot()); 

     // the usual stuff here 
    } 
} 

Quando si pratica pura dI, in genere vedere il tuo composit La radice ionica consiste in una lunga lista di dichiarazioni if. Un'istruzione per oggetto root nell'applicazione.

L'avvio con Pure DI presenta alcuni vantaggi interessanti. Il più importante è il supporto in fase di compilazione, perché è qualcosa che perderai immediatamente quando inizi a utilizzare una libreria DI. Alcune librerie cercano di minimizzare questa perdita consentendo di verificare la configurazione in un modo che il compilatore farebbe; ma questa verifica viene eseguita in fase di esecuzione e il ciclo di feedback non è mai così breve come quello che il compilatore può darti.

Si prega di non essere tentati di semplificare lo sviluppo implementando un meccanismo che consente di creare tipi utilizzando la riflessione, perché in tal modo si sta costruendo la propria libreria DI. Ci sono molti aspetti negativi a questo, ad es. si perde il supporto per la compilazione del tempo senza recuperare i benefici che una libreria DI esistente può darvi.

Quando la radice di composizione sta diventando difficile da mantenere, è il momento in cui dovresti prendere in considerazione il passaggio da DI puro a una libreria DI.

Do notare che nella mia radice composizione di esempio, tutti componenti applicative (ad eccezione per i controllori) sono definiti come Singleton. Singleton significa che l'applicazione avrà solo un'istanza di ciascun componente. Questo progetto richiede che i componenti siano privi di stato (e quindi sicuri per i thread), qualsiasi cosa abbia lo stato (ad esempio BooksContext) should not be injected through the constructor. Nell'esempio ho utilizzato uno Func<T> come provider dello BooksContext che viene memorizzato per richiesta.

Rendere i vostri singleton grafici di oggetti ha molti vantaggi interessanti. Ad esempio, ti impedisce di fare errori di configurazione comuni come Captive Dependencies e ti costringe a un design più SOLIDO. Inoltre, alcune librerie DI sono molto lente e rendere tutto singleton può impedire problemi di prestazioni quando si passa a una libreria DI in seguito. D'altro canto, il lato negativo di questo design è che tutti i membri del team dovrebbero capire che tutti i componenti devono essere apolidi. Lo stato di conservazione nei componenti causerà dolore e aggravamento inutili. La mia esperienza è che i componenti stateful sono molto più facili da rilevare rispetto alla maggior parte degli errori di configurazione DI.Ho anche notato che avere componenti singleton è qualcosa che sembra naturale per molti sviluppatori, specialmente per quelli che non hanno esperienza con DI.

Si noti che nell'esempio ho implementato manualmente uno stile di vita per richiesta per BooksContext. Sebbene tutte le librerie DI abbiano un supporto immediato per gli stili di vita con scope come gli stili di vita per richiesta, non farei uso di quegli stili di vita con ambito (tranne forse quando la libreria garantisce di lanciare un'eccezione invece di fallire silenziosamente). La maggior parte delle librerie non ti avvisa quando risolvi un'istanza di ambito al di fuori del contesto di un ambito attivo (ad esempio risolvendo un'istanza per richiesta su un thread in background). Alcuni contenitori ti restituiscono un'istanza singleton, altri ti restituiscono una nuova istanza ogni volta che chiedi. Questo è davvero fastidioso perché nasconde bug e può causare molte ore nel tentativo di eseguire il debug dell'applicazione (parlo per esperienza qui).

0

Ninject e l'unità forniscono contenitore di oggetti, che contiene oggetto wich avete registrati all'avvio dell'applicazione,

Ma perché è necessario utilizzare di, Di afferma che due oggetti non dovrebbero dipendere dalla sua concreation essa dovrebbe dipendere sulla sua astrazione, quindi se supponiamo in futere devi sostituire la classe Book con eBook, qui entrambi la classe ha la stessa funzione ma ha diffront concreation in quel momento è necessario solo il tuo di configurazione non hai bisogno di ricodificare il controller per eBook.

Sto usando unità di nei miei progetti più di fronte a qualsiasi problema che non riesco a risolvere facilmente e faccio pratica per usarlo, non aver paura per questo.

0

Se si è interessati solo a Dependency Injection per ottenere un certo livello di astrazione, non è assolutamente necessario utilizzare alcun framework IoC.

Se non si cura di portata, durata e le dipendenze nidificate, si può finire con qualcosa di così primitivo come questo:

internal class MyBasicResolver : IDependencyResolver 
{ 
    private readonly Dictionary<Type, Type> _services = new Dictionary<Type, Type>() 
    { 
     { typeof(IBook), typeof(Book) } 
     // more services registrations 
    }; 


    public object GetService(Type serviceType) 
    { 
     return _services.ContainsKey(serviceType) ? Activator.CreateInstance(_services[serviceType]) : null; 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     yield return GetService(serviceType); 
    } 
} 

quindi registrarlo come l'attuale dipendenza Resolver per MVC:

DependencyResolver.SetResolver(new MyBasicResolver()); 

Vedi MSDN

9

La soluzione più semplice e più sana è quella di utilizzare Pure DI. Con ASP.NET MVC, questo è più facilmente fatto derivante da DefaultControllerFactory e prioritario GetControllerInstance:

protected override IController GetControllerInstance(
    RequestContext requestContext, Type controllerType) 
{ 
    if (controllerType == typeof(Test)) 
     return new Test(new Book()); 

    return base.GetControllerInstance(requestContext, controllerType); 
} 

Quindi registrare il suo nuovo di fabbrica Controller è in Global.asax come questo:

ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory()); 

Purtroppo, gran parte la documentazione indicherà l'utilizzo di IDependencyResolver o Bastard Injection per gestire l'iniezione delle dipendenze, ma these will not make your code more maintainable.

Ci sono molti altri dettagli, inclusi esempi di come utilizzare correttamente l'iniezione delle dipendenze con ASP.NET MVC, in my book.

+2

Grazie Marco. Il tuo libro è nella mia lista dei desideri in Amazon :). – RKh

Problemi correlati