SPA mit ASP.NET Core und Angular

Einfache Datenzugriffsschicht anlegen

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
ASP.NET MVC Core setzt grundlegend auf Dependency Injection. Am Beispiel einer einfachen Datenzugriffschicht erfahren Sie in diesem Film, wie Sie eigene Abhängigkeiten registrieren und nutzen.
17:54

Transkript

In meinem Controller, den wir hier sehen, habe ich eine Methode Get, die eine Liste von Speisen zurückgibt. Diese Liste, die habe ich im Moment hart kodiert und zwar gebe ich hier einfach nur eine Speise, nämlich den Fantasie Salat zurück mit den Resten aus der Küche. Natürlich wäre es an dieser Stelle etwas schöner, wenn ich tatsächlich echte Daten zurückliefern könnte. Und echte Daten, die habe ich mir bereits in einer Datei abgelegt, die ich Ihnen einmal kurz zeigen möchte. Und zwar habe ich in meinem Übungsordner einen Ordner Demo Daten und diese Daten, die können Sie dann auch gemeinsam mit dem Projekt herunterladen. Und hier habe ich die beiden Dateien dishes.json und categories.json. In diesen Dateien sind also die Daten enthalten, die ich gerne über meinen Dishes-Controller zurückgeben möchte und dazu werde ich jetzt zunächst einmal einen neuen Ordner anlegen in meinem Projekt. Den nenne ich dann data und zu diesem Ordner, zu dem werde ich dann schließend die beiden Dateien hinzufügen. Dazu wechsle ich am einfachsten wieder in den Explorer und werde die einfach per Drag&Drop jetzt hier hereinziehen. So, den Explorer kann ich wieder zumachen. Und wenn wir uns die Dateien jetzt einmal ansehen, dann sehen wir also, dass das Inhaltsateien sind und das hier die einzelnen Speisen enthalten sind. Hier zum Beispiel der Salat nach Art des Hauses und die Tomatensuppe, die Gemüsesuppe, gegrillte Paprika, was auch immer. So, diese Datei dishes.json, die würde ich jetzt gerne über meinem Dishes-Controller und zwar hier über die Methode Get zurückgeben. Jetzt wäre ein Weg natürlich, dass ich hingehe und hier direkt die Datei öffne, das Ganze deserealisiere und dann zurückgebe. Das möchte ich aber nicht in meinem Controller machen, denn diese Controller, die sollten möglichst schlank gehalten werden. Die dienen nur als äußere Fassade, also als äußerer Einsprungspunkt und delegieren dann die Arbeit weiter. Bedeutet, ich werde mir eine eigene Klasse schreiben, die diese Daten für mich liest, deserealisiert und dann an den Controller übergibt. Jetzt gibt es dafür verschiedene Ansätze, wie man so etwas macht und ein Ansatz besteht darin, dass man zum Beispiel das Repository-Muster umsetzt. Da gibt es viel für und wie das man in diesem Muster umsetzen möchte oder nicht, ich zeige Ihnen das einfach einmal, wie Sie das machen könnten und ob Sie dann das Repository-Muster oder zum Beispiel das Command-Query-Segregation-Muster umsetzen wollen. Das ist dann später natürlich Ihnen überlassen. Also ich wähle hier HinzufügenNeuer Ordner und diesen Ordner nenne ich Repositories. Für mein Repository werde ich jetzt eine Schnittstelle anlegen. Eine Schnittstelle deswegen, weil ich nicht möchte, das mein Controller eine feste Abhängigkeit auf dieses dateibasierte Repository hat, sondern stattdessen von einer Abstraktion abängig ist. Das gibt mir später die Möglichkeit die Daten zugefügt auszutauschen und zum Beispiel das Enter DI-Framework an der Stelle zu nutzen oder eben auch meinen Controller mit Unitest zu überprüfen. Aber diese Schnittstelle, die lege ich jetzt an. Das ist im ersten Fall eine ganz einfache Schnittstelle. Die benenne ich IDishRepository und dieses IDishRepository, was ich jetzt hier angelegt habe, diese Schnittstelle, die erhält jetzt mehrere Methoden, die mir lesenden, aber auch schreibenden Zugriff ermöglichen. Zum einen hätte ich ganz gerne eine Methode vom Typ IEnumerable, vom Typ Dish, die nenne ich GetDishes. Und die wird mir, wie Sie wahrscheinlich schon erraten haben, eine Liste von Speisen zurückliefern. Aktuell beschwert sich die Entwicklungsumgebung hier, weil der Name Dish nicht gefunden wird. Also Steuerung+Punkt und den entsprechenden Namensraum importieren. Und wenn das geschehen ist, ist auch hier der Fehler weg und jetzt kann ich weitermachen. Und ich hätte gerne eine Methode, die gibt mir alles zurück. Dann hätte ich ganz gerne eine Methode, die gibt mir genau eins zurück. Also ein Objekt vom Typ Dish und die nenne ich zum Beispiel GetDishById und dann muss ich natürlich die ID übergeben. Ansonsten kann die ja nicht anhand der ID eine Speise zurückgeben. Dann wäre es ganz hilfreich, wenn ich eine Methode zum Anlegen hätte. Und da beim Anlegen die darunterliegende Datenquelle vielleicht meine Daten verändert. Zum Beispiel wird vielleicht die ID automatisch generiert. Aus diesem Grund übergebe ich nicht nur hier eine Speise, sondern ich gebe auch eine Speise zurück, nämlich die neu erzeugte. Wenn wir das Anlegen können, dann wollen wir es häufig auch ändern. Also definiere ich eine Methode UpdateDish und zu guter Letzt sollten wir auch die Chance geben, wieder eine zu löschen. Die gibt jetzt nichts zurück, sondern die löscht einfach anhand der ID. So, soweit ist meine Schnittstelle fertig. Jetzt wäre es also Zeit diese zu implementieren. Dazu lege ich mir hier eine weitere Klasse an und diese Klasse, die nenne ich jetzt FileDishRepository, weil die eben auf Basis von Dateien später arbeiten wird. Diese Klasse, die implementiert jetzt die Schnittstelle IDishRepository. Und jetzt kann ich mir einen kleinen Trick zum Beispiel nehmen. Ich kann auch hier Steuerung+Punkt drücken und kann jetzt bei den Schnellaktionen auswählen, dass Visual Studio für mich die Schnittstelle implementieren soll. Natürlich kann Visual Studio für mich nur das Grundgerüst herstellen, denn eine sinnvolle Implementierung, die kann es nicht automatisch machen. Dementsprechend steht jetzt hier auch überall ein throw new NoImplement and Exception. Aber ich möchte ganz gerne diese Methode hier implementieren, die mir also alle Gerichte liefert. Und dazu brauche ich den Pfad zu dieser Datei hier. Dann muss ich die lesen und anschließend kann ich das dann deserealisieren. Diesen Pfad, dort hinten den, erhalte ich über ASP.NET Core über einen Objekt vom Typ IHostingEnviroment. Dieses hat nämlich die Eigeschaft ContentRootPath, also das ist der tatsächliche Basispfad meiner Anwendung. Und darüber kann ich mich dann später weiter durchhangeln. Dieses Objekt vom Typ IHostingEnviroment, das kann ich jetzt hier nicht selber erzeugen in der Klasse. Und deswegen lasse ich das von außen an den Konstruktor meiner Klasse übergeben. Dazu habe ich über das ctor-Schnipsel gerade eine Konstruktor angelegt und sage jetzt hier, naja, wenn jemand einen FileDishRepository erzeugen möchte, dann muss der ein IHostingEnviroment-Objekt übergeben. Und das nenne ich hier env und diese Schnittstelle IHostingEnviroment, die befindet sich im Namensraum Microsoft asp.netcore Hosting. Allein, dass ich das Objekt jetzt erhalten habe, das hilft mir noch nicht. Ich kann jetzt hingehen und kann das benutzen, um mir zum Beispiel den Pfad auszulesen. Und dazu definiere ich mir jetzt hier oben ein Feld. Das ist ein Private Readonly String. Readonly bedeutet in dem Zusammenhang, dass ich das nur im Konstruktor ändern kann das Feld und das nenne ich _path. Und hier weise ich dem jetzt einen Wert zu, indem ich hier sage path = Path.Combine Und path befindet sich jetzt als Klasse im Namensraum System IO. Da gibts die Methode Combine. Damit kann ich also einzelne Bestandteile eines Pfades zu einem gesamten Pfad zusammenfügen. Und der erste Teil den ich habe, das ist mein mein ContentRootPath. Das ist also der Pfad, in dem meine Anwendung später laufen wird. Dann übergebe ich Data. Das ist also dieser Unterordner hier. Natürlich muss das dann aber ein string sein und zu guter Letzt übergebe ich noch den Dateinamen, nämlich dishes.json. Damit habe ich dann im Konstruktor einen Pfad angelegt, der genau auf diese Datei zeigen wird. Zum Auslesen muss ich jetzt folgendes machen; ich muss erst einmal den Inhalt lesen. Und das geht relativ einfach. Ich definiere mir hier eine Variable, die nenne ich json. Das wird gleich ein string werden und hier gibt es an der Klasse File die statische Methode ReadAllText. Da wird also der gesamte Text dieser Datei ausgelesen. Und an diese Methode muss ich den Pfad zu der Datei übergeben. Bedeutet, an dieser Zeile hier habe ich also jetzt den kompletten Inhalt der Datei einmal in einer Variable vom Typ string gespeichert. Als nächstes muss ich das Ganze dann deserealisieren und da kann ich json.net nutzen. Das wird also automatisch als Referenz hinzugefügt bei so einem Webprojekt. Jetzt sind wir hier bei den Abhängigkeiten. Da gehört das zu einem der Unterpunkte hier. Wahrscheinlich ist das hier in dem Core.Mvc drin. Hier sollten wir irgendwo Newtonsoft.Json drinstehen haben, irgendwo in dieser Abhängigkeitskette hier. Wo es genau drin ist, finde ich auf die Schnelle nicht. Auf jeden Fall ist es irgendwo in meinen Abhängigkeiten drin. Und was ich jetzt nur machen muss ist, ich muss den Namensraum importieren, also using Newtonsoft.json, der steht jetzt hier oben entsprechend drin und dann gibt es hier die Methode DeserializeObject. Jetzt muss ich aber den generischen Typparameter anegeben, was für einen Objekttyp ich überhaupt deserealisieren möchte. Und zwar hätte ich ganz gerne ein IEnumerable vom Typ Dish und zwar anhand der Daten, die sich in der Variable json befinden. Der Aufruf hier, der gibt mir jetzt also eine Auflistung von Dish-Objekten zurück und das ist ja genau das, was wir hier auch zurückgeben wollen. Also sage ich hier jetzt noch return und dann gibt mir diese Methode alle Gerichte zurück, die wir haben. So, was muss ich jetzt in meinem Controller machen? In meinem Controller gehe ich nun hin und lösche diese Dummy-Implementierung und definiere jetzt hier eine Variable vom Typ IDishesRepository und importiere schnell den Namensraum. Die heißt Repository und die kann auch Readonly sein. Die werde ich also nur im Konstruktor verändern. Und jetzt kann ich hier dieses Repository benutzen und kann einfach hier angeben return_repository.GetDishes Damit haben wir den Controllercode natürlich schon enorm entschlackt, aber das reicht noch nicht ganz, denn aktuell hat diese Variable hier noch den Wert Null. Bedeutet also, ich muss hier nicht nur deklarieren, sondern initialisieren. Jetzt kann ich das Repository hier nicht selber von Hand erzeugen, weil ich ja diese Kette habe, dass ein HostEnviroment-Objekt herein muss und so weiter. Dann ist der Trick hier, dass ich auch hier wieder Dependency Injection benutze. Bedeutet ich definiere einen Konstruktor und sage, ich brauche hier, damit ich funktioniere als Controller, ein Objekt vom Typ IDishRepository und das nenne ich hier Repository. Und das ,was hier übergeben wird bei der Erzeugung des Controllers, das weise ich dann diesem Feld oben zu. Bleibt schlussendlich nur die Frage offen, woher weiß den überhaupt die ASP.NET-Laufzeitumgebung, was an diesen Konstruktor übergeben werden muss. Und die Antwort lautet, aktuell weiß die Laufzeitumgebung das noch gar nicht. Das müssen wir ihr mitteilen. Und zwar gibt es in der Klasse Startup die Methode ConfigureServices. Und hier kann ich folgendes machen. Ich habe hier dieses Objekt vom Typ ServiceCollection und hier habe ich jetzt die Möglichkeit zu sagen Add und jetzt kann ich hier entweder sagen AddTransient oder AddScoped, was ich wählen werde. Und was diese beiden Methoden machen ist folgendes, ich kann jetzt hier eine Schnittstelle registrieren, zum Beispiel IDishRepository, so, Namensraum schnell importieren und kann anschließend eine Implementierung dieser Schnittstelle noch weiter angeben. Dadurch weiß jetzt die ASP.NET-Laufzeitumgebung, aha, wenn zur Laufzeit eine Abhängigkeit vom Typ IDishRepository angegeben wird, dann kann dort ein Objekt vom Typ FileDishRepository reingegeben werden. Über AddScoped sage ich, dass innerhalb von einer Anfrage, also einem Webrequest immer dasselbe FileDishRepository genutzt werden soll. Alternativ hätte ich auch AddTransient wählen können und wenn ich das wähle, dann wird an jede Stelle, wo so ein Repository benötigt wird, wird immer ein neues hereingegeben. Aus meiner Sicht macht das nicht so viel Sinn. Für mein Repository, da ist also AddScoped der bessere Lebenszyklus. So, jetzt habe ich hier eine ganze Menge geändert. Wir probieren es einmal schnell aus, ob es funktioniert und danach erkläre ich Ihnen nochmal Schritt für Schritt, was ich im einzelnen gemacht habe, um jetzt hier die Daten tatsächlich darstellen zu können. So, ich will nicht auf api/values, sondern api/dishes und das sieht schon sehr voll aus. Und noch besser sehen wir das im Postmap. Hier wird die gleiche Abfrage nochmal nochmal lossenden und da sehen wir es auch sehr schön formatiert. Wir sehen also, dass hier jetzt genau die Daten aus meiner Datei über den Controller zurückgegeben werden. Wie aber nochmal der Weg dorthin? Schritt Nummer eins bestand drin, dass ich die Daten erstmal zu meinem Projekt hinzugefügt habe, nämlich innerhalb des Ordners Datas habe ich diese Datei Dishes.json abgelegt. Schritt Nummer zwei war, dass ich mir eine Datenzugriffsschicht geschrieben habe. Ich habe mich jetzt hier für das Repository-Muster entschieden, habe zunächst eine Schnittstelle definiert. Hier habe ich sämtliche Methoden definiert, die später implementiert werden müssen. Dann habe ich eine Implementierung dazu angelegt, die aktuell sämtliche Methodenrümpfe angibt, aber nur die Methode GetDishes tatsächlich auch implementiert. Der Kernpunkt hier war, dass ich an den Pfad herankommen muss. Und diesen Pfad zu der Datei, dazu brauche ich den Ausgangspfad zu der Anwendung. Und diesen Ausgangspfad den bekomme ich von einem Objekt vom Typ IHostinEnviroment. Und das kann ich mir über Dependency Injection von außen hereingeben lassen. Genauso habe ich über Dependency Injection auch mein Repository in meinen Dishes-Controller geben lassen. Dazu musste ich allerdings in der Datei Startup im Bereich ConfigureServices die Verbindung zwischen Schnittstelle und konkreter Implementierung zunächst herstellen. Wir haben also an dieser Stelle gesehen, ASP.NET MVC Core legt sehr viel Wert auf eine lose Kopplung. Das Framework ist von Grund auf auf Dependency Injection ausgelegt und genau das haben wir in diesem Video uns auch gemeinsam jetzt am Beispiel von einer Datenzugriffsschicht einmal angesehen.

SPA mit ASP.NET Core und Angular

Lernen Sie die Bestandteile von modernen Webanwendungen kennen und nutzen.

5 Std. 21 min (36 Videos)
Derzeit sind keine Feedbacks vorhanden...
Hersteller:
Exklusiv für Abo-Kunden
Erscheinungsdatum:25.09.2017

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!