Hallo zusammen,
ich versuche mich zur Zeit in das Thema Dependency Injection einzuarbeiten und nutze dazu Ninject.
Ich habe mehrere Anwendungen, die mit demselben Datenmodell arbeiten für sich gesehen aber spezielle Anforderungen haben.
Nun wollte ich die Validierung des Models (mittels FluentValidation auslagern und in eine eigene Assembly packen. Der geeignete Validator für ein Modell soll per DI bereitgestellt werden. Deswegen dachte ich mir, dass man die Registrierung dieser Typen innerhalb der Validation-Assembly vornehmen sollte.
Das Model wird unter anderem von einer ASP.NET WebApi 2 Anwendung verwendet. Diese hat auch Typen, welche per DI bereitgestellt werden sollen. Also bekommt die Anwendung auch eine "DI-Konfiguration".
Dies ist die Stelle, an der ich nicht mehr weiter weiß. Ist dieser Ansatz überhaupt gut gewählt und wenn ja, wie baut man das mit z.B. Ninject nun auf?
Teilen sich alle Komponenten ein und dieselbe Ninject-Kernel-Instanz oder gibt es mehrere?
Muss man dediziert einen Kernel erzeugen und diesen dann durch die Komponenten zur Registrierung ihrer Typen durchreichen?
Ich hoffe ihr könnt etwas Licht ins Dunkel bringen und mir weiterhelfen.
Gruß,
wax
edit: Titel auf Unity geändert
Ich empfehl Dir auf NInject zu verzichten und auf Unity zu setzen.
In der nächsten Version von ASP.NET (Core 1) wird nämlich Unity (bzw. DI-Container, der Unity sehr sehr sehr ähnlich ist) direkt mitgeliefert.
Bin mir nicht sicher, ob ich Dich richtig verstanden hab; aber ich setze dies so um, dass meine Business-Schicht ebenfalls einen Resolver hat, den ich dann Unity in ASP.NET bekannt mache.
So kann ich Di ohne Aufwand in allen Anwendungstypen (ASP.NET, Console...) nutzen.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hi Abt,
ich habe mich nun mit Unity auseinandergesetzt.
Mein Ansatz ist zur Zeit der, dass ich den IUnityContainer zur Registrierung der Typen durch die Projekte reiche. Dazu benötigen ich von meiner Composition Root aus aber immer Referenzen auf die Implementierungs-Prjojekte, da nur diese Interface UND Implementierung kennen.
Da muss doch was falsch sein. Ich dachte man würde nur an den Interfaces hängen!? So ist mein "Main"-Projekt ja weiterhin von den Impl-Projekten abhängig.
Wie macht man sowas?
Gruß,
wax
Hallo Wax,
ich bin mir nicht sicher, ob ich dich richtig verstanden habe. Aber ich hatte auch mal die Frage hier im Forum gestellt, dass bei der Registrierung meine Klassen mein Root auch immer auf die *.Impl-Projekte verweisen muss, da man sie ja sonst nicht registrieren kann. Ich finde den Thread aber gerade nicht mehr...
Jedenfalls war die Antwort, dass man vom Root aus einfach damit lebt, dass eine Referenz auf das Impl-Projekt ist und es nur dort verwendet, wo es in den DI Container geschmissen wird. Andere Verweise sollten dann immer über das Interface/API-Projekt laufen.
Ich suche den Thread mal weiter...
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Naja, i.a macht man bei seinen Plugin fähigen Projekten ja ein Interface fürs ModulInit, das dann das Registrieren der Objekte/Klassen im übergebenen ( I ) Container übernimmt.
So muss nur das Modul die konkrete Implementation kennen.
Ich halte nichts von Impl-Projekten - wir sind ja nicht bei Java. 😃
Dependency Injection ist nicht dazu da, dass man die vollkommene Unabhängigkeit bekommt und die Referenzen nicht kennen muss.
Spätestens beim Zugriff auf den jeweiligen Typ muss man die Referenz haben - oder im Falle von DI das entsprechende Interface.
Bei mir erzeugt in den Projekten i.d.R. die Middleware / Engine den Unity-Container.
using BenjaminAbt.TestApp.Engine.Factories;
using BenjaminAbt.TestApp.Engine.Registrators;
namespace BenjaminAbt.TestApp.Engine
private EngineBoostraper()
{
_container = new UnityContainer();
_container.RegisterType<IQueryFactory, AssemblyCachedQueryHandlerFactory>();
_container.RegisterType<ICommandFactory, AssemblyCachedCommandHandlerFactory>();
CommandRegistrator.Register( _container );
QueryRegistrator.Register( _container );
}
Die Engine bzw. das Registering hat dann die Referenzen, zumindest auf die Interfaces bzw. beim Registrieren auch auf die Typen.
namespace BenjaminAbt.TestApp.Engine
public static void Register( IUnityContainer unityContainer )
{
unityContainer.RegisterType<IPersonsQuery, PersonsQuery>( nameof( PersonsQuery ) );
unityContainer.RegisterType<IPersonByIdQuery, PersonByIdQuery>( nameof( PersonByIdQuery ) );
}
Die Applikation (hier als Beispiel WebAPI), die aber den Unity-Container hält, muss die Implementierungen nicht kennen!
namespace BenjaminAbt.TestApp.WebApp
public static void Register( HttpConfiguration config )
{
var container = EngineBoostraper.Container;
config.DependencyResolver = new UnityResolver( container );
namespace BenjaminAbt.TestApp.WebApp.Persons
public class PersonsController : ApiController
{
private readonly IQueryFactory _queryFactory;
public PersonsController( IQueryFactory queryFactory )
{
_queryFactory = queryFactory;
}
Wenn jetzt der Controller nicht im Hauptprojekt sondern in einem Modul ist, dann kennt das WebAPI Projekt keine einzige Referenz ausser zum EngineBootstrapper.
Die Plugins selbst können ja über viele Wege in die AppDomain kommen (oder man gibt ihnen den Container).
Und das ist der riesige Vorteil (oder ich hab Deine Frage nicht verstanden).
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
@Abt: Könntest du bitte einmal deine Aussage "Ich halte nichts von Impl-Projekten - wir sind ja nicht bei Java. 😃" begründen. Würde mich interessieren.
Gruß,
wax
Keine Ahnung, worauf Du nun hinaus willst...
Aber in Java ist es ja oft so, dass diese auf nen Präfix beim Interface verzichten, dafür die Implementierung eines Interfaces mit Impl dekorieren
public class Socket : ISocket
public class SocketImpl
implements Socket {
Und ich halte nichts davon (C#), wenn man in Projekt MyName.MyProject.Socket.Interfaces
seine Interfaces deklariert und MyName.MyProject.Socket.Impl
für die Implementierung nutzt.
Weiß jetzt nicht, ob das jetzt Coffeebean so macht (hoffentlich nicht 😃 ) aber ich hab sowas schon oft gesehen.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Weiß jetzt nicht, ob das jetzt Coffeebean so macht (hoffentlich nicht 🙂 ) aber ich hab sowas schon oft gesehen.
Ich wusste, dass sowas kommt. 😉 Hab nur drauf gewartet.
Hat alles Vor- und Nachteile. Da ich bei vielen verschiedenen Kunden im Einsatz bin und war habe ich das auch schon oft gesehen. Ich sage das ohne Wertung an der Stelle Aber es stimmt: Oft haben die Impl-Leute Java-Vergangenheit. ("Impl" bezüglich Klassennamen, Namespaces oder sogar auf Projekt-Ebene)
Aber die Diskussion ob das gut oder schlecht ist lassen wir an der Stelle bleiben!
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck