9

Ich bin neu in Repository und DI und versuche, in meinem MVC 5-Projekt zu implementieren.Verwenden von Abhängigkeitsinjektion ohne DI-Bibliothek

I umgesetzt Constructor Injection, wo in meinem Controller einen Konstruktor wie folgt hat:

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

Ohne DI Bibliothek, wirft er einen Fehler: Es gibt keine leeren Konstruktor ist.

dies zu vermeiden, habe ich, wie unten mehr Konstruktor ein:

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

Da ich an DI bin hier, ich will nicht mein Projekt zu wagen durch DI-Bibliothek, die später einige Fehler werfen, dass Ich kann es vielleicht nicht lösen.

Ich möchte wissen, welche Probleme ich auftreten könnte, wenn ich keine DI-Bibliothek verwende.

Falls es empfehlenswert ist, welche DI-Bibliothek für Anfänger geeignet ist? Ich habe einige Videos von NInject und Unity gesehen.

+4

Ich würde SimpleInjector empfehlen, da es die Konfiguration vor dem Start überprüft. Sehr wenige Container machen das. So würde jedes Problem in der Regel am Anfang gefunden und gelöst werden. – jgauffin

+0

Wenn Sie irgendwann planen, Ihr Projekt auf ASP.NET vNext zu aktualisieren, ist es erwähnenswert, dass einige grundlegende Implementierungen von DI-Containern enthalten sind, die Ihren Anforderungen entsprechen (http://blogs.msdn.com/b /webdev/archive/2014/06/17/dependency-injection-in-asp-net-vnext.aspx) –

+1

Ich denke, dass es viel besser wäre, mit Pure DI zu beginnen, anstatt ASP.NET vNext eingebauten DI zu verwenden Bibliothek. [Die integrierte DI-Bibliothek ist nutzlos, wenn Sie SOLID-Anwendungen schreiben] (https://stackoverflow.com/a/30682214/264697). – Steven

Antwort

16

Es ist eine gute Idee, die Entscheidung, eine Art Werkzeug oder Bibliothek zu verwenden, bis the last responsible moment zu verschieben. Mit einem guten Design können Sie später eine DI-Bibliothek hinzufügen. Dies bedeutet, dass Sie Pure DI üben.

Der bevorzugte Interceptionspunkt in MVC ist die IControllerFactory Abstraktion, da es Ihnen ermöglicht, die Erstellung von MVC-Controllern abzufangen, und dies verhindert, dass Sie einen zweiten Konstruktor implementieren müssen (is an anti-pattern). Obwohl es möglich ist IDependencyResolver, die Verwendung dieser Abstraktion zu verwenden ist viel weniger praktisch, weil es auch von MVC zu lösen Dinge genannt wird man in der Regel nicht daran interessiert ist.

Ein benutzerdefinierte IControllerFactory, die als composition root handeln kann umgesetzt werden wie folgt:

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; 
    } 
} 

kann Ihre neue Controller Fabrik in MVC angeschlossen werden, wie folgt:

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

     // the usual stuff here 
    } 
} 

Wenn Sie reine DI üben, werden Sie in der Regel Ihre composit sehen Ionenwurzel bestehen aus einer großen Liste von if Aussagen. Eine Anweisung pro Stammobjekt in Ihrer Anwendung.

Der Anfang mit Pure DI hat einige interessante Vorteile. Am bekanntesten ist die Kompilierzeit-Unterstützung, da Sie diese sofort verlieren werden, wenn Sie eine DI-Bibliothek verwenden. Einige Bibliotheken versuchen, diesen Verlust zu minimieren, indem Sie Ihre Konfiguration auf eine Weise verifizieren, die der Compiler durchführen würde. aber diese Überprüfung wird zur Laufzeit durchgeführt und der Rückkopplungszyklus ist nie so kurz wie der, den der Compiler Ihnen geben kann.

Bitte seien Sie nicht versucht, die Entwicklung zu vereinfachen, indem Sie einen Mechanismus implementieren, der das Erstellen von Reflektionstypen ermöglicht, da Sie damit Ihre eigene DI-Bibliothek erstellen. Es gibt viele Nachteile, z.B. Sie verlieren die Kompilierzeit-Unterstützung, ohne die Vorteile einer vorhandenen DI-Bibliothek zu erhalten.

Wenn Ihr Kompositionswurzel schwer zu warten wird, sollten Sie in diesem Moment den Wechsel von Pure DI in eine DI-Bibliothek in Betracht ziehen.

tun, dass in meiner Beispiel Zusammensetzung Wurzel zu beachten, alle Anwendungskomponenten (mit Ausnahme des Controller) als Singleton definiert. Singleton bedeutet, dass die Anwendung nur eine Instanz jeder Komponente hat. Bei diesem Design müssen Ihre Komponenten zustandslos (und damit threadsicher) sein, alles, was einen Status hat (z. B. BooksContext) should not be injected through the constructor. Im Beispiel habe ich einen Func<T> als Provider des BooksContext verwendet, der pro Anfrage gespeichert wird.

Die Erstellung von Objektgraphen, Singletons, bietet viele interessante Vorteile. Zum Beispiel verhindert es häufige Konfigurationsfehler wie Captive Dependencies und zwingt Sie in ein solideres Design. Darüber hinaus sind einige DI-Bibliotheken sehr langsam, und alles, was ein Singleton ist, könnte Performance-Probleme beim späteren Wechsel zu einer DI-Bibliothek verhindern. Auf der anderen Seite ist der Nachteil dieses Entwurfs, dass jeder im Team verstehen sollte, dass alle Komponenten zustandslos sein müssen. Das Speichern des Zustands in Komponenten führt zu unnötigem Kummer und Ärger. Nach meiner Erfahrung sind zustandsbehaftete Komponenten wesentlich leichter zu erkennen als die meisten DI-Konfigurationsfehler.Ich habe auch bemerkt, dass Singleton-Komponenten etwas sind, das für die meisten Entwickler natürlich ist, besonders für jene, die keine Erfahrung mit DI haben.

Beachten Sie, dass ich im Beispiel manuell eine pro-Anforderung Lebensstil für die BooksContext implementiert. Obwohl alle DI-Bibliotheken Out-of-the-Box-Unterstützung für bestimmte Lebensstile wie Lebensläufe pro Anfrage bieten, würde ich mich dagegen aussprechen, diese eingeschränkten Lebensstile zu verwenden (außer vielleicht, wenn die Bibliothek sicherstellt, dass eine Ausnahme ausgelöst wird). Die meisten Bibliotheken warnen Sie nicht, wenn Sie eine Bereichsinstanz außerhalb des Kontexts eines aktiven Bereichs auflösen (z. B. wenn Sie eine pro-Request-Instanz in einem Hintergrundthread auflösen). Einige Container geben Ihnen eine Singleton-Instanz zurück, andere geben Ihnen bei jeder Anfrage eine neue Instanz zurück. Das ist wirklich lästig, weil es Bugs versteckt und Sie viele Stunden lang versuchen lässt, Ihre Anwendung zu debuggen (ich spreche aus Erfahrung hier).

0

Ninject und Einheit bieten Objektcontainer, das Objekt enthält weicht Sie beim Start der Anwendung registrieren,

Aber warum Sie di verwenden müssen, sagt Di, dass zwei Objekte sollten nicht von seiner concreation abhängen sollte es abhängen auf seiner Abstraktion, also wenn Sie in funere müssen Sie Buchklasse zu eBook ersetzen, hier hat die Klasse die gleiche Funktion, aber es hat unterschiedliche concreation zu dieser Zeit müssen Sie nur Ihre Di-Konfiguration müssen Sie nicht den Controller für eBook neu codieren.

Ich benutze Unity di in meinen meisten Projekten, die ich didt jedes Problem, das ich nicht lösen kann, ist es einfach und machen Praxis, das zu nutzen, fürchten Sie nicht davor.

0

Wenn Sie nur an Dependency Injection interessiert sind, um ein gewisses Abstraktionsniveau zu erreichen, müssen Sie keinesfalls ein IoC-Framework verwenden.

Wenn Sie nicht über Umfang, Lebensdauer und verschachtelten Abhängigkeiten kümmern, können Sie mit etwas so primitiv, wie dies am Ende:

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); 
    } 
} 

Dann registrieren sie als aktuelle Abhängigkeitsauflöser für MVC:

DependencyResolver.SetResolver(new MyBasicResolver()); 

Siehe MSDN

9

Die einfachste und vernünftigste Lösung zu verwenden Pure DI ist. Mit ASP.NET MVC wird dies am einfachsten durch von DefaultControllerFactory Ableiten getan und überwiegenden GetControllerInstance:

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

    return base.GetControllerInstance(requestContext, controllerType); 
} 

Dann Ihre neue Controller Factory in Ihrem Global.asax wie folgen registrieren:

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

Leider viel Dokumentation wird Ihnen empfehlen, IDependencyResolver, oder Bastard Injection mit Dependency Injection zu behandeln, aber these will not make your code more maintainable.

Es gibt viele weitere Details, einschließlich Beispielen für die ordnungsgemäße Verwendung von Dependency Injection mit ASP.NET MVC unter my book.

+2

Danke Mark. Dein Buch befindet sich in meiner Amazon Wunschliste :). – RKh