Laden...

Wie benutze ich Dependency Injection im Business Layer richtig?

Erstellt von Duesmannr vor 3 Jahren Letzter Beitrag vor 3 Jahren 1.171 Views
D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren
Wie benutze ich Dependency Injection im Business Layer richtig?

Moin,

ich will in meinen BLL Projekten die Interfaces von den dazu gehörigen DAL via DJ verwenden. Aber auch andere BLL nutzen können.

Mit der Aussage von Abt, dass man dafür evtl. ein neues Projekt erstellen kann, was das ganze Thema dann behandelt.

Um die Wiederverwendbarkeit zu erhöhen kann man natürlich ein MyProject.Register Projekt haben, an dem das dann zentral Konfiguriert wird.
Aber DI ist kein Common!

Link zum Zitat

Und hab mir das noch angesehen
Trennung der Schichten zur Businesslogik (Services) und Daten (Repository Pattern) ASP.net MVC5

Bleibt bei mir die Frage, wie ich das ganze umsetzen soll.
In ASP.NET Core zB ist das direkt implementiert.

Mein Projekt besteht aus:
DAL => BLL (zwei Projekte, dotnet standard 2.1)

Einmal ein bisschen Code:
ILanguageDAL:


public interface ILanguageDAL
{
        Translation GetTranslation(string identifier, StringComparison stringComparison = StringComparison.Ordinal);
}

Wie ich das derzeit instanziiere:


public class LanguageBLL : ILanguageBLL
{
    #region Fields

    private readonly ILanguageDAL languageDAL;

    #endregion

    public LanguageBLL()
    {
        this.languageDAL = new LanguageDAL();
    }
}

Nur werde ich durch die Posts hier im Forum nicht schlau, wo es auch aus Beiträgen nicht ersichtlich ist, wie man es umsetzen soll.
Ebenfalls auch nicht von Google.
In der BLL will ich zukünftig dann noch andere BLL implementieren können, via DJ.
Ich weiß das ich dafür Helper brauche, womit ich die Interface instanziiere und die dann beim Konstruktor Aufruf geladen werden. Bzw. auch ein Framework, was das behandelt, aber nicht zu einem krassen Overhead besitzt.

Wie der Automapper und der Mapper von Abt im Vergleich zum Overhead.

Nur wie, keine Ahnung.

In der Firma wo ich arbeite, machen die beispielsweise mit einem Mapping und erstellen diese dann mit dem Microkernel. Ich will das nur gerne via DJ, falls es geht.

Gibt es da evtl. ein Topic was das evtl. ein wenig beschreibt oder Schlüsselbegriffe, wonach ich suchen kann, wo ich evtl. nicht drauf komme?

Grüße

16.807 Beiträge seit 2008
vor 3 Jahren

Dependency Injection hat an nichts mit dem Layer zutun; das kann überall eingesetzt werden.
Auch der AutoMapper ist keine Pflicht.

DI (nicht DJ) kann an jeder Stelle und in jeder Anwendungstechnologie verwendet werden.
ASP.NET Core ist bezogen auf das .NET Ökosystem die aktuellste Technologie; daher ist hier - nach langer Community-Forderung - ein DI-System direkt eingebaut.
In allen anderen (Desktop Apps, Konsolen Apps, Windows Services, Mobile Apps, Functions..) kann auch DI verwendet werden; nur ist das eben nicht von Haus aus mit an Bord.

Bezogen auf Dein Beispiel und ASP.NET Core:

public class LanguageBLL : ILanguageBLL
{
    private readonly ILanguageDAL _langdal;

    public LanguageBLL(ILanguageDAL langdal)
    {
        _langdal = langdal;
    }
}

Dann eben noch die Dinge registrieren:

services.AddScoped<ILanguageBLL, LanguageBLL>();
services.AddScoped<ILanguageDAL, LanguageDAL>();

Ein zusätzlichen Helper brauchst Du nicht.
Der DI Provider löst automatisch alle Abhängigkeiten in einem Konstruktor auf, sofern die jeweiligen Typen (meist Interfaces) im Container registriert sind.

Dokumentiert ist das übrigens alles in den Fundamentals: Dependency injection in ASP.NET Core.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren

Dependency Injection hat an nichts mit dem Layer zutun; das kann überall eingesetzt werden.

Ist mir bewusst.

Auch der AutoMapper ist keine Pflicht.

Hatte ich nur in nem Thread gelesen, dass der Overhead von Automapper zu groß ist. Von dir.

Bezogen auf Dein Beispiel und ASP.NET Core:

Wie das dann umgesetzt wird, weiß ich auch.

Ein zusätzlichen Helper brauchst Du nicht.
Der DI Provider löst automatisch alle Abhängigkeiten in einem Konstruktor auf, sofern die jeweiligen Typen (meist Interfaces) im Container registriert sind.

Genau darum gehts. Es geht nicht um ASP.NET Core, WPF oder sonstiges, sondern um den DI Provider. Wie ich den in meinem Fall implementiere. Und den Provider ggfs. in ein anderes Projekt auslagere. Aber wie ich den implementiere, keine Ahnung. Bzw. auch welches Framework ich dafür verwenden kann.

Edit:
In dem Link wird ja ASP.NET Core verwendet und da hast du das ja direkt implementiert.
Was bei mir ja nicht der Fall ist.

16.807 Beiträge seit 2008
vor 3 Jahren

Es wäre toll, wenn Du meine Aussage aus 2016 nicht aus dem Zusammenhang reisst.

Der AutoMapper war damals nicht für das Anwendungskonstrukt von ASP.NET Core gemacht (und vor allem nicht im Zusammenhang mit dem DbContext).
Der Fokus von AutoMapper damals war vor allem Desktop-Anwendungen.

Seit dem Zeitpunkt meiner Aussage hat der AutoMapper jedoch an vielen Stellen eine deutliche Verbesserung erhalten; inbesondere mit den Queriable Extensions und ProjectTo, sodass der AutoMapper und dessen Overhead bei korrekter Anwendung einer untergeordnete Rolle spielt.

Der AutoMapper unterstützt ebenfalls DI; alles dokumentiert.
Dependency Injection

Aber wie ich den implementiere, keine Ahnung. Bzw. auch welches Framework ich dafür verwenden kann.

Mh, wozu brauchst Du ein Framework bei externen Bibliotheken?
Könntest Du evtl. mal Dein Problem erklären?

Was meinst Du mit "den implementiere"? Du implementierst den Provider - sofern Du damit "den" meinst - gar nicht.
Dependency Injection funktioniert so, dass Du Abhängigkeiten im Konstruktor bekannt machst statt innerhalb der Klasse eine konkrete Abhängigkeit durch die Instantiierung zu schaffen.
Die Registrierung erfolgt immer in der Anwendung selbst.

Ansonsten muss ich sagen, dass das nen ganz wirres Thema ist.
Hier wird irgendwie DI, AutoMapper und Software Architektur im Sinne der Layer so vermischt, wie es für mich zumindest nicht nachvollziehbar ist, worum es eigentlich geht.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren

Es wäre toll, wenn Du meine Aussage aus 2016 nicht aus dem Zusammenhang reisst.

War nicht mein Ziel. War nur als vergleich mit dem Overhead.
Für ein Framework was DI als NuGet ermöglicht.

Dependency Injection funktioniert so, dass Du Abhängigkeiten im Konstruktor bekannt machst statt innerhalb der Klasse eine konkrete Abhängigkeit durch die Instantiierung zu schaffen.
Die Registrierung erfolgt immer in der Anwendung selbst.

Wie DI funktioniert weiß ich.
Es geht darum, dass ich das DAL Interface via DI erhalte, losgelöst in welchem Projekt die oben genannten Interfaces genutzt werden, weil diese in diversen Projekten benutzt werden sollen.
Aber das mit dem DAL wäre ein nice2have, weil ich n-BLL Klassen habe, die ich auch in n-BLL Klassen verwenden möchte. Und diese will ich dann nicht immer wieder hard instanziieren, sondern einfach im Konstruktor übergeben haben möchte.
Ich hoffe du verstehst jetzt, was ich meine.

Edit:
Also theoretisch habe ich ein Projekte, was mir DI ermöglicht, ich dann eine Methode von außerhalb aufrufen kann, wodurch ich ein Singleton hinzufügen kann.

Und das wird durch eine Methode (Initialize) alles erstellt, die dann im eigentlichen Projekt aufgerufen werden muss (ASP.NET Core, WPF, whatever..)

Hier wird irgendwie DI, AutoMapper und Software Architektur im Sinne der Layer so vermischt[...]

AutoMapper war nur im Bezug auf den Overhead von 2016 bezogen.
Die eigentliche Frage bezieht sich auf DI.
Was in meinem Fall die oben genannte Architektur ist, wo es genutzt werden soll.

16.807 Beiträge seit 2008
vor 3 Jahren

Ich verstehe nicht wieso dein Klassenbibliothek die DI Umgebung kennen muss und wieso du da ein Framework brauchen würdest.
Das ist eigentlich nicht notwendig.

In der Anwendung selbst kann man einfach das Microsoft Dependency Injection Framework verwenden.
Aber wie gesagt; der Klassenbibliothek ist das egal, die braucht keine Abhängigkeit zum DI.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren

Anbei ein Foto zur Veranschaulichung.

In den BLL werden andere BLL gebraucht.

Ohne DI würde hier BLL1 2 mal instanziiert werden usw.

Ich würde in dem Fall gerne DI einbauen, damit
BLL1 und BLL3 nur einmal instanziiert wird und nicht zweimal.

Und das halt alles in Klassenbibliotheken, unabhängig von der Anwendung, die die Libraries einbindet.

16.807 Beiträge seit 2008
vor 3 Jahren

Les dir nochmal durch wie DI funktioniert:

  • Bekanntmachung der Abhängigkeiten über den Konstruktor
  • registrieren der Abhängigkeiten im DI Container
    > Der Rest passiert automatisch.

Du musst nichts extra in den Klassenbibliotheken implementieren.
Den Link zur Doku wie der DI von Microsoft funktioniert ist oben. Da steht alles drin.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren
  • registrieren der Abhängigkeiten im DI Container

Die Sache ist nur, dass ich nicht in der Anwendung, die die Libraries einbindet, alle Singletons hinzufügen will, die in den ganzen Libraries genutzt werden.

Und ich das dann potenziell auch nicht weiß, wenn ich die Libraries für meine Projekte über NuGet verteile.

16.807 Beiträge seit 2008
vor 3 Jahren

Ah, nach mehreren Beiträgen ist mir nun klar was du willst.

Eine Klassenbibliothek ist I.d.R. nicht der Verantwortung zu entscheiden ob sie als Singleton oder nicht verwendet wird.
Das entscheidet die Anwendung bzw die Umgebung.

Du kannst natürlich eine eigene Extensions ala AddMyService() anbieten wie es auch das EntityFramework macht; ist aber nur sehr selten wirklich notwendig.
Das ist dann aber auch eine Abhängigkeit zum DI Provider.
Machen einige Bibliotheken, dann jeweils als extra / zusätzliches NuGet Paket.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren

Du kannst natürlich eine eigene Extensions ala AddMyService() anbieten wie es auch das EntityFramework macht; ist aber nur sehr selten wirklich notwendig.

Da ist dann die Frage, wie ich das umsetze. Weil in der Microsoft Doku immer von der Startup Klasse ausgegangen wird.

Machen einige Bibliotheken, dann jeweils als extra / zusätzliches NuGet Paket.

Das meine ich mit Framework, die mir DI ermöglicht.

16.807 Beiträge seit 2008
vor 3 Jahren

Du baust dir gerade Dein Problem selbst zusammen, das Du eigentlich gar nicht hast.
Du solltest dem Nutzer deiner Klassen erklären wie man diese richtig verwendet, aber schreibe ihm nicht vor welches DI Framework er zu nutzen hat, geschweige denn schreibe ihm nicht vor ob es ein Singleton ist oder nicht.

Deine NuGet Pakete sollten keine Abhängigkeiten zu einem DI Framework haben, wenn dies nicht für die Funktionsweise notwendig ist.
Für dein Vorhaben ist das offenbar nicht Mal notwendig.

Und nein, die Microsoft Dokumentation geht nicht immer von einer Startup-Klasse aus.
Das ist nun Mal die Dokumentation von ASP.NET; nicht vom ganzen .NET Universum.

Das gleiche Framework kann auch für WPF und functions genutzt werden und da zeigt die Doku keine Startup, weil es die da einfach nicht gibt.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren

Also meinst du, dass ich bei der Dokumentation dem Entwickler sagen soll
Dass er irgendein DI Framework nutzen muss und dann eine Liste mit Interfaces und Klassen dazu schreibe, die registriert werden müssen?

So funktionierts:


var services = new ServiceCollection()
                .AddSingleton<ILanguageDAL, LanguageDAL>()
                .AddSingleton<ILanguageBLL, LanguageBLL>();

            ServiceProvider serviceProvider = services.BuildServiceProvider();

            ILanguageBLL bllService = serviceProvider.GetService<ILanguageBLL>();

            bllService.GetTranslation("");

Mit dem Nuget Package "Microsoft.Extensions.DependencyInjection.Abstractions".
Ist jetzt in meinem Test Projekt.

1.029 Beiträge seit 2010
vor 3 Jahren

Hi,

es gibt wirklich keinen Grund, weshalb deine Klassen in diesem Format überhaupt das Prinzip DI kennen sollten.

Beispiel:
Deine Controller in ASP.NET Core - die wissen nichts von DI - die haben im Normalfall schlicht einige Parameter im Konstruktor. Einfach um bei der Anwendung die Freiheit zu erhalten ob und wenn ja welches DI-Framework zum Einsatz kommt.

Wenn die Klasse überhaupt was vom DI-Framework weiß - oder sogar via DI die eigenen Abhängigkeiten auflöst - hast du effektiv Murks gemacht. DI machst du ja eben für lose Kopplung / leichte Austauschbarkeit - und nicht um die Kopplung noch zu verkomplizieren...

Um auf dein Beispiel zurückzukommen:
Wenn BLL1 die BLL2 braucht - dann bekommt sie diese eben per Konstruktor. In der eigentlichen Anwendung (dort in der Startup z.B.) kann man das dann gerne als Singleton via DI umsetzen - aber diese Funktionalität so vorzuschreiben ist in der Regel keine so tolle Idee, da du dann die Verwendung von DI vorschreibst und damit eine Kopplung (zur Microsoft DI) vorschreibst, welche sich überhaupt nicht austauschen lässt.

LG

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren

Um auf dein Beispiel zurückzukommen:
Wenn BLL1 die BLL2 braucht - dann bekommt sie diese eben per Konstruktor. In der eigentlichen Anwendung (dort in der Startup z.B.) kann man das dann gerne als Singleton via DI umsetzen[...]

Moin Taipi,

dass ist ja mein Plan, dass ich die einzelnen BLL via Konstruktor erhalte, was ja möglich ist.
Das Problem ist nur, dass ich irgendwo die ganzen Singletons registrieren muss. Ja dies wird eigentlich in der Startup Klasse gemacht oder halt da, wo das Programm gestartet wird.

Nur ist das Beispiel oben von mir eine Library die ich via NuGet an meine Projekte verteile. Und will dennoch DI nutzen können.

Da komm ich dann zu meiner letzten Frage zu Abt

Also meinst du, dass ich bei der Dokumentation dem Entwickler sagen soll
Dass er irgendein DI Framework nutzen muss und dann eine Liste mit Interfaces und Klassen dazu schreibe, die registriert werden müssen?

Das ich dem Entwickler(mir) dann eine Liste mit Singletons gebe, die registriert werden müssen, damit die Library funktioniert.

Und das ist auch keine schöne Lösung, deswegen hatte ich hier erhofft eine Lösung zu finden 😃

16.807 Beiträge seit 2008
vor 3 Jahren

Nochmal: DI hat in deinem NuGet nichts zu suchen.
Was du hier baust ist ein Anti-Pattern; angefangen vom Service Locator, den du hier zeigst über die zusätzlichen Abhängigkeiten, die nicht notwendig sind.

Schau bitte endlich in die Doku wie DI funktioniert und warum die Bibliothek niemals bestimmen sollte ob sie ein Singleton ist oder nicht.
Du konstruiert dir hier dein eigenes Problem zusammen und untergräbst den Sinn von DI.

Aber wenn du trotzdem.den Anti-Pattern weg gehen willst, dann ist das halt so.
Keiner kann dich dazu zwingen das sein zu lassen.

Wenn die NuGet Pakete nur zusammen funktionieren, dann willst du offenbar / vielleicht nur ein Architekturfehler mit DI lösen; aber leider auf einem falschen Wege.

1.029 Beiträge seit 2010
vor 3 Jahren

Achso - das kannst du dir doch von ASP.NET Core abspicken.

In deiner späteren Anwendung (abseits der Library) wirst du ja sicher etwas ähnliches haben wie die Startup-Klasse - nur dass du es dort wahrscheinlich übersichtlich/einfach halten willst. (Zumindest für Standard-Konfigurationen)

Hab das auch für einige (zugegeben ASP.NET Core basierte) libs gemacht. Schreibst dir einfach einer Helper-Klasse, die solche Services und deren Abhängigkeiten in Standardkonfiguration in der DI einträgt. So sind die einzelnen Komponenten nach wie vor unabhängig und die Verwendung wird trotzdem nicht unübersichtlich, solange der Standard genügt.

Als simple Beispielklasse dafür:


namespace Microsoft.Extensions.DependencyInjection
{
public static class YourNameHereConfigurationExtension
{
public static IServiceCollection ConfigureYourNameName(this IServiceCollectionb services)
{
// your di-registrations here....
}
}
}

Durch eine solche Klasse hast du keine Nachteile - und sogar Microsoft hat's vorgemacht.
(ConfigureMVC, ConfigureLogging, etc.)

Abseits dieser Helfer-Klasse allerdings - ist jegliche Verwendung von DI (oder sogar ServiceLocator) ein Fehler, der dir später bitter aufstoßen wird.

LG

Edit:
Ich hab eine solche Helfer-Klasse z.B. für die Registrierung des DataServices. Da bekommt die Helferklasse die Möglichkeit an bestimtme Konfigurationselemente ranzukommen - und je nach dem was konfiguriert wurde - werden dann eben spezifische DB-Implementierungen (Mssql, Mysql, etc.) in die ServiceCollection eingefügt.

16.807 Beiträge seit 2008
vor 3 Jahren

Der Nachteil ist die Abhängigkeit zur ServiceCollection und damit zum DI Provider. Und DI hat im eigentlichen Paket selbst nichts zu suchen, ausser.man will die Abhängigkeit.
Daher lagert man sowas in extra NuGets aus, wie es Microsoft und die Community auch zeigt.
Beispiel AutoMapper: https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection

Dabei gilt:

  • Erweiterungsmethoden auf IServiceCollection beginnen mit Add..()
  • Erweiterungsmethoden auf IApplicationBuilder beginnen mit Use..(). Configure..() ist reserviert für Konfigurationen.

Aber das hatten wir weiter oben schon; riecht eher alles nach einem Workaround für ein Konzeptionsfehler.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 3 Jahren

Ja sowas meine ich Taipi, dass wäre ein Lösungsansatz.
Nur gibt es dann halt die Abhängigkeit wie Abt richtig gesagt hat.

Ich guck mir mal das Repo von AutoMapper an.