ASP.NET Core Full Course Subtitles Download – .NET 10 Tutorial
ASP.NET Core Full Course For Beginners (.NET 10)
Julio Casal
SRT - Most compatible format for video players (VLC, media players, video editors)
VTT - Web Video Text Tracks for HTML5 video and browsers
TXT - Plain text with timestamps for easy reading and editing
Scroll to view all subtitles
Heute lernst du, wie du eine vollständige REST-API mit ASP.NET
Core und C# schrittweise erstellst.
Wir starten ganz von vorn, Endpunkte erstellen, eine Datenbank über
Entity Framework Core verbinden und Validierungen hinzufügen.
Du lernst Dependency Injection, asynchrone Programmierung und auch, wie
man eine saubere Code-Struktur bewahrt.
Am Ende verbindest du deine API mit einem modernen React-Frontend und
siehst, wie alles funktioniert, ja.
Legen wir los.
Ihr Unternehmen baut einen Videospiel-Shop auf.
Das Frontend-Team hat das Spielkatalog-UI bereits erstellt.
Ihre Aufgabe besteht darin, das Backend zu entwickeln, das es antreibt.
Alle Spieldaten werden in einer Datenbank gespeichert, und Sie stellen die Daten
über eine REST-API mit Endpunkten zum Erstellen, Lesen, Aktualisieren
und Löschen von Spielen bereit.
Dieser Kurs zeigt Ihnen, wie man dieses Backend von Anfang bis Ende
mit ASP.NET Core und C# erstellt.
Sie beginnen damit, zu lernen, wie man Ihre erste ASP.NET Core-Anwendung von
Grund auf erstellt, ausführt und debuggt.
Danach gehen wir auf die Kernkonzepte hinter REST-APIs ein und zeigen, wie man
die traditionellen CRUD-Endpunkte in einer ASP.NET Core API schnell implementiert.
Beim Implementieren Ihrer REST-API prüfen Sie DTOs genau, um den Vertrag zwischen
Ihrer API und dem Frontend festzulegen.
Dann wirst du sehen, wie man Erweiterungsmethoden und Routengruppen
nutzt, um API-Endpunkte gut zu ordnen.
Du wirst auch Zeit verbringen, ungültige Eingaben testen, um zu lernen, wie
sie von deiner API behandelt werden.
Als Nächstes führen Sie die Datenbankunterstützung über das
beliebte Entity Framework Core ein, das in der .NET-Plattform enthalten ist.
Dies bietet zudem eine Chance, das ASP.NET Core-Konfigurationssystem
wirklich kennenzulernen, das Hardcodierung vermeidet und Konfigurationsdetails
in Ihrem C#-Code erleichtert.
Als Nächstes erläutern Sie Designmuster der Abhängigkeitsinjektion und
wie die Laufzeit von Diensten in ASP.NET Core funktioniert.
Hier lernst du, wie du Entitäten auf DTS abbildest, damit der Datenvertrag
mit Frontend flexibel bleibt und das Datenmodell erhalten bleibt.
Sie schließen Ihre Risik-API-Implementierung ab, indem
Sie das asynchrone Programmiermodell einführen, damit Ihre Anwendung
die Ressourcen des Webservers möglichst effizient nutzt.
Und zum Abschluss zeige ich Ihnen, wie Ihre REST-API gut in das Frontend
integriert wird, um eine moderne Benutzererfahrung zu ermöglichen.
Um mitzukommen, brauchen Sie auch zwei Dinge: das .NET SDK, das es Ihnen
ermöglicht, .NET-Anwendungen zu erstellen und auszuführen, und Visual Studio Code.
Den Editor verwenden wir im Kurs.
Wir fügen auch VS Code-Erweiterungen hinzu, die ich dir im Kurs zeige.
SDK und VS Code installiert.
Mal sehen, wie man Ihre Entwicklungsumgebung einstellt.
Lassen Sie uns sehen, wie man Visual Studio Code für die
.NET-Entwicklung einrichtet.
Als Erstes sollten wir prüfen, ob .NET ordnungsgemäß auf dem Rechner
installiert ist; dazu können wir die .NET-Kommandozeile oder CLI verwenden.
Zu diesem Zweck öffnen wir das Terminal von VS Code, das wir
über die Menüleiste finden können.
Genau hier jetzt.
Öffnen wir das Terminal und dann ein neues Terminal.
Und hier ein kurzer Tipp.
Man kann die Strg-Tilde-Verknüpfung verwenden, um das Terminal sehr schnell
zu öffnen und wieder zu schließen.
Oder unter Windows geht das auch.
Du kannst Strg-J verwenden, das hat denselben Effekt.
Jetzt klicke ich hierher, um dieses Terminal für einen kurzen
Moment zu vergrößern, damit es den gesamten Bildschirm ausfüllt.
Und jetzt geben wir einfach net ein, das uns Zugriff auf das .NET C# ermöglicht,
und danach tippen wir --version ein.
Und das, wie man sehen kann, zeigt uns schließlich die aktuelle
Version des Install.NET SDK an.
Eine weitere Sache hier: Falls ich das schnell erledige, tippen
Sie Do net info, das uns mehr Informationen über die installierte
Version von net S C# K liefert.
Wie Sie sehen, enthält net S C# K alle Details.
Außerdem erhalten Sie Details zu Windows und viele weitere
Informationen darüber, was Sie in Bezug auf .NET installiert haben.
Da wir alle Informationen ohne Probleme abrufen konnten, ist
unsere Installation korrekt.
Jetzt klicken wir hier auf dieses Papierkorb-Symbol,
um das Terminal zu beenden.
Und gehen wir zum nächsten Schritt über, der die Installation
eines Add-ons ist, das unsere C#-Diagrammentwicklungserfahrung in
PS Code sehr deutlich verbessern wird.
Dafür öffnen wir die Erweiterungsansicht auf der linken Seite.
Und hier möchten wir Folgendes jetzt tun: Wir suchen nach einer
Erweiterung namens C# Sharp Dev Kit, die hier Ihre erste Wahl sein sollte.
Dies ist ein C# Sharp Dev Kit.
und dies wird die Haupt-Erweiterung sein, die entworfen wurde.
Um dir beim Erstellen von C#- und .NET-Anwendungen in VS Code zu helfen.
Lasst uns hier auf das Widget klicken.
Und nachdem es fertig ist, sollten wir schnell sein.
Ja, erledigt.
Was ich zeigen möchte: Diese Erweiterung installiert nicht
nur eine, sondern mehrere.
Also klickt hier auf dieses Widget, um unsere Box dort drüben zu leeren.
Lass mich das mal ganz kurz wirklich zusammenfassen.
Und das, was du hier siehst, wenn es sich nun zusammenfaltet, ist, dass wir jetzt
einige installierte Erweiterungen haben.
Dazu gehört hier die C#-Erweiterung, die die grundlegende Sprachunterstützung
für C# bietet, damit du die korrekte Syntaxerkennung deines C#-Codes hast.
Und diese intelligente Unterstützung.
Dann bekommst du C#, Erweiterung, die wir installiert haben, um VS
Code zu erweitern, wie den Solution Explorer, damit du Projekte und
Abhängigkeiten verwalten kannst, und mit dieser Erweiterung kannst du
Unit-Tests auch ausführen, falls nötig.
Und oben sehen wir, dass dort das NET-Installationswerkzeug vorhanden ist,
das tatsächlich eine Erweiterung ist.
Es wird von anderen Plugins wie C#-Erweiterung und C#-Kit genutzt,
um eine Version von .NET SDK oder Laufzeit zu installieren, falls
diese Plugins sie benötigen.
Wir nutzen im Kurs noch ein paar Erweiterungen, aber
vorerst ist das gut zum Start.
Brechen wir das jetzt.
Und jetzt sind wir bereit, unser .NET-Projekt zu erstellen.
Wie man das macht?
Nun, es gibt einige Wege, es zu tun.
Der erste Weg besteht darin, erneut das .NET-CLI zu verwenden.
Dafür öffne ich erneut mein Terminal.
Hier ist mein Terminal.
Und was du tun kannst, ist net new list einzugeben und Enter zu drücken.
Und was das bewirkt, ist dir eine vollständige Liste
aller Vorlagen zu zeigen.
Für verschiedene Arten von Anwendungen, die mit deinem .NET bzw.
C# beginnen können.
Nun, wenn du doch mal ganz zum Anfang gehst,
Wir bemerken, dass der dotnet-CLI erste Informationen darüber
liefert, was Sie installiert haben.
Telemetrie und Details werden nicht behandelt, das lasse ich.
Das zeigt nur beim ersten Mal, die eigentliche Liste ist hier.
Das ist die Liste deiner Vorlagen, mit der du verschiedene Apps erstellen kannst.
Also, falls Sie eine brandneue und leere ASP.NET Core-App wirklich
erstellen möchten, könnten Sie das hier verfügbare Web-Template verwenden.
Von hier aus könnten Sie Folgendes tun: Lassen Sie mich das kurz klären.
Sie könnten dotnet new web verwenden und ihm einen Namen geben.
Zum Beispiel installieren Sie diese API, und damit wird Ihre Web-App erstellt.
Doch das ist nur ein Weg, es zu tun.
Und seit wir das C#-Chart-Kit geklaut haben.
Wir haben einen besseren Weg.
Also beende ich Terminal erneut.
Und diesmal gehen wir in unsere VS Code-Befehls-Palette, die wir erreichen,
indem wir erneut in unser Menü gehen.
Lass uns die Befehls-Palette öffnen.
Und nochmals ein kurzer Hinweis: Verwende die folgende Tastenkombination,
um schnell dorthin zu gelangen.
Unter Windows kannst du Strg+Shift+P drücken, und damit öffnet sich
diese Palette sehr schnell.
Die Farbpalette ist wirklich sehr nützlich.
Es ist gut, schnell darauf zuzugreifen.
Jetzt kannst du einfach type.net eingeben, und das zeigt dir alle
Befehle, die derzeit mit dem .NET SDK verbunden sind, wie du sehen
kannst, ohne weitere Schritte.
Der erste Befehl ist der .NET New Project-Befehl, mit dem wir unser Projekt
erstellen und damit direkt starten.
Lass uns darauf klicken.
Nochmals erhalten Sie die vollständige Liste aller installierten .NET-Vorlagen,
die Sie verwenden können, um Ihre Apps in Visual Studio Code zu erstellen.
Nun zu Zwecken des Kurses.
Eine der Vorlagen, die Sie verwenden könnten, um Ihr Projekt
zu erstellen, wäre die ASP.NET Core Web-API-Vorlage, die hier verfügbar ist.
Und diese hier wäre ideal, wenn Sie bereits etwas Erfahrung mit der
Entwicklung von Web-APIs in .NET haben.
Allerdings empfehle ich diese hier nicht.
Wenn Sie ganz neu in solchen Anwendungen sind, wird das eine Menge Dateien
und Konfigurationen mit sich bringen.
Das könnte gleich verwirrend sein.
Stattdessen empfehle ich dir, wirklich mit der A-Vnet-Core-leeren
Vorlage zu beginnen.
die dir eine saubere Grundlage mit wenigen Dateien verschafft,
damit du loslegen kannst.
Dort kannst du starten, Code und Dateien hinzuzufügen, während du genau
verstehst, wofür jedes Teil gedacht ist, während du sie integrierst.
Lass uns fortfahren und auf ASP.NET Core Empty klicken.
Lass mich in meinen Projektordner wechseln.
Und hier möchten wir den Ordner erstellen, der künftig als
Arbeitsbereich für unsere Arbeit in Business Studio Code dienen wird.
Und da wir an einer Spiele-Shop-Anwendung arbeiten, erstelle ich ganz
einfach einen brandneuen Ordner, den wir Store nennen werden.
Okay.
Ich geh in Ordner.
Dann wähle ich den Ordner aus.
Dann trag ich den Namen unserer App ein.
Nennen wir es.
Game Store API, denn es wird die NET-Risk-API sein.
Lass uns Endtiefe erreichen.
Und hier bitten wir um das Format unserer Lösung.
Reichen Sie die Lösung in .NET ein.
Das ist es, was VS Code sagen wird, und zwar welche Projekte du bearbeiten
wirst und wie sie zusammenhängen.
Dieses SLN ist echt die alte Version und nicht praktisch.
SLNX ist die neuere, modernere Version.
Also empfehle ich dir, l und X zu wählen, wo möglich.
Also nimm jenes.
Und zuletzt klicken wir auf Projekt erstellen, damit das Projekt entsteht.
Ich schließe hier das Terminal, indem ich auf die drei Punkte klicke.
Dann öffne ich das Terminal und klicke auf den Papierkorb.
Und wie Sie sehen.
Wir haben dort unseren neuen Game-Store-API-Ordner, der unser
.NET-Projekt enthält, der hier liegt, zusammen mit einer ganzen Reihe
weiterer Dateien, die unsere bisherige .NET-Anwendung vollständig ausmachen.
Bevor wir uns die erzeugten Dateien im Detail ansehen, gibt es zwei
Wege, wie man diese Projektdateien sinnvoll durchsuchen kann.
Der erste Weg besteht darin, den Dateiexplorer zu verwenden, den du
standardmäßig geöffnet vorfindest.
Also hier ist dein Dateiexplorer, und hier handelt es sich um eine physische Ansicht.
Damit wird wirklich jede einzelne Datei deines Projekts sichtbar gemacht.
Wie Sie sehen können, betreffen Ihre Lösungsdatei und sogar Ihr Dasein
als OVA-Verzeichnis hier nicht das Thema, das man gleich besprechen
wird; aber es gibt auch noch etwas.
Eine weitere Ansicht, bekannt als Lösungs-Explorer, die
Sie unten sehen können.
Wenn Sie dies erweitern, und vielleicht klappen wir es kurz zusammen,
hier ist der Lösungs-Explorer.
Dies stammt vom C# Sharped Kit, und dies wird eher eine virtuelle
Ansicht Ihrer Anwendung sein.
Was nur die schnellere Version zeigt, die vor allem für Ihre C#-
und R-Entwicklung relevant ist,
Und dir die Fähigkeit geben, einfach mit dem Erstellen zu beginnen.
Verschiedene C#-R-Dateien.
Zum Beispiel kannst du hier rechts klicken und Dateien erstellen, wie du siehst.
Und du kannst Beziehungen zwischen Projekten herstellen, NOGA-Pakete
installieren und ein paar weitere Dinge.
Wir verwenden in diesem Kurs beide Explorer-Ansichten, doch die meiste Zeit
bevorzuge ich hier den Datei-Explorer, weil er sehr übersichtlich zeigt,
was in diesem Projekt geschieht.
Nun gehen wir die erzeugten Dateien durch und sehen uns die C-Programme an, das ist
die einzige Quelldatei, die wir haben.
Lass mich das hier zusammenklappen.
Und der Zweck dieser Datei besteht darin, den Code festzulegen, der
Ihre Anwendung startbereit macht
Insbesondere ist das Hauptziel hier, eine Instanz dieses App-Objekts
zu erstellen, das tatsächlich als Webanwendungsobjekt fungieren wird.
Wie Sie sehen können, möchten wir eine Instanz der Webanwendung
erzeugen, und am Ende hier möchten wir sie ausführen, ganz konkret.
Aber was ist diese Webanwendung hier drüben, die wir als Host kennen?
Dies ist der Host deiner App, und der Zweck davon ist es, eine
HGTP-Server-Implementierung für deine App einzuführen, damit du beginnen
kannst, HG-HTTP-Anfragen abzuhören.
Nun, wie Sie sehen, erstellen wir nicht einfach direkt die Web-App-Optik.
Stattdessen nutzen wir Builder-Muster über diesen Create-Builder-Optic hier.
Und das liegt daran, dass wir dieses Builder-Objekt verwenden, um eine Reihe
von Diensten für die App zu konfigurieren.
Wie Sie es mit dem Builder jederzeit tun können, und Sie werden sehen, dass
hier viele Funktionen und Methoden gibt.
Um Dienste, Konfigurationen und vieles für App festzulegen,
wie wir sie in Scores sehen.
Von dort rufen wir die Build-Methode auf, die zudem mit einer Reihe
von Standardeinstellungen für unsere Anwendung kommt, etwa die
Nutzung des Castrale-Webservers.
Das Auslesen von Einstellungen aus Apps, JSON-Datei oder Umgebungsvariablen, und
wie Login-Dienste konfiguriert werden.
All das passiert durch den Build-Aufruf hier, der das Web-App-Objekt erzeugt.
Also dieser Abschnitt hier, zwischen Zeile eins und … Ein Abschnitt, in dem wir
alle Dienste der Anwendung konfigurieren.
Und dann, sobald die Anwendung vorhanden ist, wechseln wir in den zweiten
Abschnitt über, in dem festgelegt wird, was in der HTTP-Pipeline geschieht,
also was passieren wird, wenn diese HTTP-Anfragen in die Anwendung gelangen.
Zum Beispiel hier drüben, standardmäßig, wie man sehen kann.
Wir definieren, dass eine Anfrage, die über GET Burp an die Anwendung gerichtet
wird – die ROT-Anwendung –, einfach mit einer einfachen Hallo-Welt-Zeichenkette
beantwortet wird, die dann wieder in die Farbe zurückkehrt.
Und die letzte Zeile hier wird nun den Start der Ausführung der Anwendung
auf dem Castrale-Webserver einleiten.
Wir werden im Verlauf der Punkte noch viel mehr über Pro Cs erfahren.
Vorerst schließen wir das.
Gehen wir in unseren Datei-Explorer zurück und werfen wir kurz auf
unseren Spielstore, API und CS-Profil.
Dies wird als die Projektdatei bezeichnet.
Die Datei ist allen Netzanwendungen gemeinsam, in diesem Fall.
Es enthält genau diesen SDK-Eintrag, der Microsoft .NET verwendet, das SDK-Web.
Dies legt fest, um welchen Typ von Anwendung es sich hier eindeutig handelt,
in diesem Fall eine Webanwendung.
Äh, dies wird alle Bibliotheken importieren, die speziell für
.NET-Webanwendungen entworfen wurden.
Noch eine wichtige Sache hier: Das Ziel-Framework.
Wie Sie hier sehen können,
Das Ziel-Framework bestimmt die APIs, die Ihrer Anwendung zur Verfügung stehen.
Wenn Sie eine niedrigere Version verwenden, haben Sie weniger
APIs zur Verfügung; bei einer höheren Version stehen Ihnen mehr
und neuere APIs zur Verfügung.
In diesem Fall verwende ich .NET 10, wie man dort sieht, ganz
deutlich, denn das ist die Version.
Ich nutze es Standard, als ich Projekt machte.
Jetzt schließen wir das hier und gehen in unsere appsettings.json,
diese JSON-Datei hier.
Diese Datei und auch appsettings.json für die Entwicklung sind die Dateien, die
du verwenden kannst, um Konfigurationen zu definieren, die du nicht hart
in deinem C#-Code codieren willst.
JSO ist Standarddatei, die verwendet wird.
In jeder Umgebung gibt es außerdem ABS-Abwesenheit der JSO-Entwicklung,
die du lokal verwenden kannst.
Jetzt begeben wir uns hier in den Ordner Eigenschaften, dort werden wir die andere
Datei namens Launch Set Jason finden.
Und dies ist eine Datei, die eben entworfen wurde.
Um festzulegen, was Profile bedeuten.
Das Profil ist ein Ort, an dem man Einstellungen festlegen kann.
Es geht darum, wie Sie Ihre Anwendung in der lokalen Entwicklung ausführen.
Alles, was hier definiert ist, gilt ausschließlich für die lokale Entwicklung
und hat nichts mit Produktion zu tun.
Hier definieren wir es eben.
Wenn wir die Anwendung über HTTP starten möchten, wird die URL der Anwendung hier
zu sehen sein, HTTP, localhost 51 59.
Der Port wird zufällig festgelegt, wenn du ein Projekt erstellst, daher bekommst
du wahrscheinlich einen ganz anderen Port.
Wenn du deine eigene Anwendung erstellst,
Sie können hier Umgebungsvariablen definieren, zum Beispiel diese
Finnet-Umgebungsvariable, die anzeigt, dass wir in einer
Entwicklungsumgebung arbeiten, nicht in der Produktionsumgebung.
Wenn Sie lokal H-G-T-P-S verwenden möchten, nutzen Sie Ihr
H-G-T-P-S-Profil, das eine URL mitbringt.
Wie hier zu sehen ist, haben wir H GT P.
S, Localhost 7083, wodurch du deine Anwendung lokal
mit HTTPS ausführen kannst.
Okay, jetzt schließen wir das hier endgültig ab.
Und noch ein paar andere Dinge, die hier genau zu beachten sind: Der Anteil
davon, insbesondere, dass es sich um OVA-Verzeichnisse handelt, wobei hier
OVJ die Zwischendateien enthält, die von .NET erzeugt werden, bevor die endgültige
Version Ihrer DLL erstellt wird.
Und diese endgültige Version wird wirklich hier in diesem Bin-Verzeichnis landen.
Zuletzt, wie hier unten zu sehen ist, haben wir unsere
S-SLX-Datei, diejenige ist.
Es versteht, welche Projekte du hier in VS Code bearbeitest
und wie sie zusammenhängen.
Die Datei treibt das Nutzererlebnis an, das du hier unten im Explorer siehst.
Wir werden im Kurs deutlich mehr über alle diese Dateien lernen.
Jetzt, da wir die Struktur unseres .NET-Projekts verstehen, schauen wir,
wie man die Anwendung baut und ausführt.
Und beginnen wir mit dem Aufbau der Anwendung.
Wie bauen wir das?
Nun, es gibt einige Wege.
Ich denke, der einfachste Weg ist, den Solution Explorer zu verwenden, damit
du im Solution Explorer arbeiten kannst.
Dort klappe ich es kurz zusammen.
Und hier musst du nur mit der rechten Maustaste auf dein Projekt klicken.
Store-API, rechts.
Dort klickst du dann bitte auf die Build-Option.
Wie du rechts sehen kannst, öffnet sich ein Terminal, und unsere Anwendung
wurde gebaut und hat es produziert.
Die Apple-DLL ist dort.
Du kannst den Prozentsatz dieser DLL prüfen, indem du
in den Datei-Explorer gehst.
Du kannst ins Bin-Verzeichnis gehen, dort findest du deine DLL und weitere Dateien.
Eine andere Möglichkeit, das zu tun, besteht darin, dein Terminal
direkt zu verwenden, richtig?
Also lasse ich mich hier tatsächlich auf ein brandneues Terminal umschalten;
ich klicke dort auf das Pluszeichen, um ein brandneues Terminal zu starten.
Und das andere beende ich, um mehr Platz zu haben.
Und von hier aus kannst du in dein Game Store dot AP-Verzeichnis wechseln,
und du kannst .NET C# verwenden.
Mit dem Build-Befehl wird es gestartet, und damit wird Ihre Anwendung
direkt vom Terminal zügig aufgebaut.
Dazu können Sie diese Vorgehensweise sowohl innerhalb von Business Studio
Code als auch außerhalb davon ausführen.
Zuletzt können Sie außerdem ganz einfach die Integration von .NET in
den Build-Task in VS Code verwenden.
Sie können dann ganz bequem Strg+Shift+B drücken, und damit wird der
Build-Task in VS Code sofort geöffnet.
Sie können auf .NET Build klicken, bitte jetzt.
Und das wird erneut den Build Ihrer Anwendung starten, heute.
Wie Sie sicher deutlich gesehen haben.
Jetzt, wie man die Anwendung ausführt.
Genau wie beim Erstellen der App gibt es auch viele Wege, die Anwendung in
VS Code auszuführen; ich halte jedoch F5 tatsächlich für den einfachsten Weg.
Also drücken wir F5, und beim ersten Mal, wenn du das machst.
VS Code wird dir zwei Fragen stellen.
Zuerst will VS Code wissen, welche Art Anwendung du ausführen willst, damit
es Werkzeuge für Ausführung nutzt.
In unserem Fall wird es eine C#-Anwendung sein, also wählen wir hier C#-Sharp.
Als Nächstes fragt VS Code nach unserer Launch-Konfig.
Es gibt hier mehrere Optionen, doch die wichtigsten sind jene, die sich auf
unsere Startprofile beziehen, die wir in unserer Startserie gesehen haben, und
die benachbarte Datei, bitte beachten.
Hier können wir HTTP-Profil starten; danach sehen wir das
HTTPS-Profil, das wir starten können.
Für den Zweck dieses Kurses, um die Dinge einfach zu halten und jegliche
Zertifikatsprobleme zu vermeiden, wählen wir die HTTP-Option, die auch
der Standardkonfiguration entspricht.
Also klicken wir auf HTTP.
Und in diesem Moment wird Visual Studio Code zuerst das Projekt erneut bauen und
dann mit der Projektausführung beginnen.
Beachten Sie, dass VS Code nicht nur unseren Webserver gestartet hat,
sondern auch einen Browser geöffnet hat, um in das Stammverzeichnis
der Anwendung zu gelangen.
Und wie Sie sehen, hier HelloWorld.
Der Grund, HelloWorld zu sehen, ist erneut; schauen wir
uns unsere Pro-CS-Datei an.
Gehen wir zurück in unsere Haupt-CS-Datei.
Lassen Sie mich das kurz zuklappen.
Wir merken uns ja, dass wann immer eine GET-Anfrage an der Wurzel
der App eingeht, die App erwartet, das Wort 'world' im Klartext
zurückzugeben, wie dort zu sehen ist.
Jetzt ist Folgendes zu beachten: Wir führen die Anwendung nicht nur aus,
sondern befinden uns im Debug-Modus, was bedeutet, dass wir Haltepunkte setzen
können, um den Zustand der Anwendung während der Ausführung zu prüfen.
Um das zu zeigen, stoppe ich die Anwendung kurz.
Dann können wir hier auf den Stop-Button klicken, um das Debuggen
zu beenden und die App zu stoppen.
Setzen wir hier in der fünften Zeile einen Breakpoint.
Lass uns das Debuggen erneut starten.
Jetzt: Statt Fünf zu drücken, zeige ich dir eine andere Möglichkeit, zu debuggen.
Öffne den Lösungs-Explorer.
Lass es hier zu.
Mit der rechten Maustaste auf deine Game-Store-API klicken
und Debug-Auswahl treffen.
Starte eine neue Instanz.
Es ist derselbe Effekt wie das Drücken der F5-Taste.
Es ist nur eine andere Art, es eben zu tun.
Beachten Sie bitte jetzt: Wir ziehen hier etwas zusammen, greifen in die
laufende Anwendung ein und untersuchen die Objekte, die gerade aktiv sind.
Wenn wir über 'up' hovern, sehen wir dort Eigenschaften, die sich
auf das App-Objekt beziehen.
Hier drüben, ja.
Auch links sehen wir.
Die hier lokalen Variablen, richtig?
Einschließlich unseres Builders und aller seiner Eigenschaften der App.
Wir könnten Beobachtungs-Ausdrücke verwenden; bei Bedarf zeigen
wir auch den Aufrufstapel.
Sie verfügen jetzt über vollständige Debugging-Unterstützung in VS Code.
Um die Ausführung fortzusetzen, werde ich hier auf den Play-Button klicken.
Wir klicken dort hinein, und dieses Mal öffnet der Browser erneut,
wie Sie sehen können, und es ist tatsächlich wieder gestoppt, denn wenn
Sie zu VS Code zurückgehen, passiert Folgendes: Wir befinden uns dieses
Mal nicht in der Startup-Sequenz, sondern im Handler für das GET-Verb.
Der Browser stellte eine GET-Anfrage an die Startseite der App,
und diesmal prüfen wir diesen Schritt, der die Antwort liefert.
Hallo?
Kehren Sie zurück, Herr.
Wir erfahren bald, wie dieses Karten-Tor funktioniert.
Später im Kurs, aber vorerst klicken wir einfach noch einmal auf den Weiter-Button.
Und zurück im Browser sehen wir dort erneut Hallo Welt.
Auch wenn es sehr nützlich sein kann, deine Anwendung mit einem angehängten
Bug zu starten, gibt es einen deutlich schnelleren Weg, deine App für deinen
normalen Entwicklungsablauf zu starten.
Wenn du wieder in VS Code gehst, stoppen wir die Anwendung erneut.
Klicke erneut auf Stopp.
Schließe dies.
Und Sie können wirklich einfach die App starten, ganz ohne Debugger.
Und was Sie tun können, ist in den Datei-Explorer zu gehen, hier in
den Solution Explorer, Rechtsklick auf Game Store API, und dann wählen
Sie jetzt 'Ohne Debuggen starten'.
Klicken Sie dort bitte.
Dadurch wird die Anwendung erneut gestartet; diesmal ist Novo angehängt.
Wie Sie gesehen haben, ist es deutlich schneller, wirklich sehr.
Es ist nicht nötig, die Live-Ausführung der App zu prüfen.
Das ist eine Möglichkeit, es zu tun.
Eine weitere Möglichkeit besteht darin, es erneut zu stoppen,
indem man STRG-F5 drückt.
Du kannst STRG-F5 drücken; das hat denselben Effekt.
Sehr einfach, dorthin zu gelangen, wie man sieht.
Und der letzte Weg besteht darin, C# direkt im .NET zu verwenden.
Nun bevor ich Ihnen das zeige, stoppen wir das hier noch mal.
Was ich zeigen will, ist, dass es eine Möglichkeit gibt, zu verhindern,
dass dieser Code den Browser öffnet.
Wie Sie sehen, sind hier mehrere Tabs offen.
Was nicht nur nicht ideal ist, aber wir arbeiten auch an
einer serverseitigen Res-API.
Das lässt sich direkt in VS Code auf einfachere Weise testen,
ohne den Browser zu verwenden.
Und ich werde dir später im Kurs noch ausführlich mehr dazu zeigen.
Aber vorerst können wir in VS Code gehen und dieses Mal in unseren
eigenen Datei-Explorer wechseln.
Gehen wir in Eigenschaften und starten das hier bei Jason gleich.
Und auch hier.
Wenn wir wieder in unser HTTP-Profil gehen, ist das hier unser HTTP-Profil.
Wir werden hier diese Eigenschaft finden, die 'Launch browser' sagt 'durch'.
Was wir tun können, ist einfach, das von Durch auf Puls umzuschalten.
damit VS Code den Browser nicht mehr öffnet und uns in der VS
Code-Umgebung dauerhaft belässt.
Also diesmal, wenn ich F5 drücke, drücke ich F5 erneut.
Hier seh ich, wie die App läuft, und wir bleiben ganz im Kontext
von VS Code, ohne Unterbrechung.
Kein Grund mehr, den Browser zu öffnen.
Okay, jetzt starte ich die Anwendung, und wie ich schon gesagt habe, kannst
du sie auch mit .NET C# ausführen.
Dafür öffne ich hier.
Lass mich in mein Terminal wechseln.
Ich beende dieses Terminal kurz.
Ich lösche den Bildschirm und vergrößere das hier ein wenig, noch ganz leicht.
und Wohlbefinden im Game Store API-Verzeichnis, an dem Ort,
an dem unser Projekt lebt.
Was du tun kannst, ist praktisch ganz einfach zu sagen, net
run, und Enter zu drücken.
Nochmals, das wird die Anwendung aufbauen und sie dann starten.
Und wie du deutlich sehen kannst,
Die Konsolenausgabe meldet den Ort unserer API, dort – Localhost, 51 59;
wir sehen, dass die App gestartet wurde.
Wir sehen unsere Hosting-Umgebung, die zurzeit nur Entwicklung ist.
In unserem Inhaltspfad hier, genau hier,
Ich bevorzuge diese Methode, um meine Domänen-App zu starten, weil
ich sofort sehe, was los ist, wenn ich hier die Konsole anschaue.
Oder nutze andere Optionen, falls sie dir besser passen.
Da wir nun wissen, wie wir unsere Anwendung bauen und starten,
wechseln wir kurz zu den Folien, damit wir REST-APIs verstehen.
Um zu verstehen, was REST-APIs sind, fange damit an, darüber nachzudenken,
welche Apps du auf deinem Telefon hast, wie Wetter-, LinkedIn- oder Spotify-Apps.
Diese Apps benötigen eine Menge Daten, doch diese Daten passen nicht auf
dein Telefon; das nennen wir Client.
Es ist zu viel, sie zu speichern, und du willst ohnehin laufend
aktuelle Daten, immer neue Daten.
Also müssen die Daten von irgendwoher kommen, und der Ort ist eine Art
Server-Rechner, der normalerweise in der Internet-Cloud liegt.
Aber wie können diese Apps mit diesem Server in der Cloud
kommunizieren, um die Daten abzurufen?
Nun, durch die Verwendung einer API.
API steht für Application Programming Interface, und es ist so, wie ein
Dienst die Funktionen definiert, die er seinen Kunden bereitstellt.
Wenn man zum Beispiel zum Spotify-Beispiel zurückkehrt, könnte
der Spotify-Cloud-Dienst eine API mit zwei Funktionen definieren.
Die Funktion zum Abrufen der neuesten Songs, nimmt den Benutzernamen als
Parameter und liefert die zehn neuesten Songs des angegebenen Nutzers zurück.
Und es könnte auch eine Abspiel-Funktion geben, die den Songname als
Parameter erhält und auch den Stream dieses Songs zurückgibt, damit
ein Client ihn abspielen kann.
So könnten dutzende oder hunderte Funktionen vom Dienst angeboten
werden, die Kunden nutzen, um mit ihm zu interagieren.
Eine API hilft den Kunden, dem Service mitzuteilen, was sie wollen, damit er
versteht und die Anfrage erfüllen kann.
Ich.
REST steht für Representational State Transfer und auch definiert eine Reihe
von konkreten Leitprinzipien, die festlegen, unter welchen konkreten
Bedingungen eine API funktionieren sollte.
In diesem Kurs gehen wir nicht auf jedes dieser Prinzipien ein, doch
wichtig ist, dass man APIs auch bauen kann, die skalierbar, flexibel und
technologieunabhängig sind, und auf dem Server wirklich funktionieren.
Also nochmals zurück zur ursprünglichen Frage: Eine REST- oder RESTful-API
folgt dem REST-Architekturstil.
Der Hauptgrund dafür, warum wir eine REST-API einrichten möchten,
besteht darin, dass unsere Clients mit den von der API verwalteten Daten
interagieren können; aber wie greifen sie tatsächlich auf diese Daten zu?
Nun ist es wirklich sehr hilfreich, zunächst das Konzept einer Ressource
in einer REST-API zu verstehen.
Eine PIA-Ressource ist jedes Objekt, Dokument oder Ding, das
die API von Clients empfangen oder an Clients senden kann.
Zum Beispiel ist in unserer Spielstore-Anwendung die
Hauptressource unsere Gewinne.
Das ist das, was die Clients abfragen und ändern wollen.
Aber in anderen Anwendungen, wie dem Spotify-Beispiel, könnte eine
der Ressourcen die Songs sein.
Und im LinkedIn-Beispiel könnte eine Ressource die Nutzer sein, und
eine weitere die LinkedIn-Beiträge.
Diese Ressourcen werden auf einer Domain gehostet, die öffentlich
sein könnte, oder auf einem Intranetstandort – oder eben Ihre Deb-Box.
Und sie können über das HTTP- oder HTTPS-Protokoll aufgerufen werden, was
in öffentlichen Umgebungen ein Muss ist.
Wenn man all diese Dinge kombiniert, erhält man die URI (Uniform Resource
Identifier), die Ihre Clients verwenden, um die Ressourcen der REST-API zu
identifizieren und darauf zuzugreifen.
Es könnten weitere Teile dieser URI existieren, aber dies sind Kernbausteine.
Nun, wie interagiert man eigentlich mit der REST-API?
Genau wie bei alten Webseiten: Wenn Clients etwas vom Server anfordern
möchten, senden sie eine HTTP-Anfrage über die passende URI an den Server, und der
Server antwortet danach mit einer Antwort.
Allerdings sehen REST-APIs und Anfragen sowie Antworten je nach der verwendeten
HTTP-Methode, mit der sie aufgerufen werden, etwas unterschiedlich aus.
Die gängigsten Methoden sind POST, mit denen neue Ressourcen erstellt werden,
GET, das die Repräsentation oder den Zustand der Ressource abruft, PUT, das
eine vorhandene Ressource aktualisiert, und DELETE, das die Ressource löscht.
Diese Methoden ermöglichen, Ressourcen zu erstellen, zu lesen,
zu aktualisieren und zu löschen.
Und daher sind sie ebenfalls allgemein als Crowd-Operationen bekannt.
Es gibt auch andere Methoden, aber für die Zwecke dieses Kurses liegt
der Fokus auf diesen vier Methoden.
Lassen wir uns die Ansätze im Kontext unseres Spielladens ansehen, um
zu sehen, wie sie funktionieren.
Ich.
Um alle Spiele abzurufen, sendet ein Client eine GET-Anfrage an den
Spiele-Endpunkt, und der Server wird bitte mit so etwas antworten.
Der erste Teil dieser Antwort ist der Status, der 200 beträgt.
Okay.
In diesem Fall bedeutet dies, dass der Vorgang ein Zugriff war.
Es gibt andere HTTP-Statuscodes, die API je nach dem Ergebnis der Operation
zurückliefert; viele sind Fehlerfälle.
Der nächste Teil ist der Körper, der die Liste der Spiele enthält.
In diesem Fall ist zu beachten, dass dieser Körper kein HTML ist, sondern das
Format der Antwort als JSON bekannt ist.
JSON steht für JavaScript-Objektnotation.
Dies ist das De facto Format zum Senden und Empfangen von Daten in REST-APIs,
da es so leicht zu lesen und zu schreiben ist und von allen gängigen
Programmiersprachen unterstützt wird.
Wenn Sie statt aller Spiele ein bestimmtes Spiel erhalten möchten,
würden Sie erneut eine Abfrage senden, aber diesmal hängen Sie am Ende den
Bezeichner der Forschung an, Nummer eins.
In diesem Fall wird der Server den Zustand des Spiels zurückmelden.
Mit diesem Bezeichner, vorausgesetzt, dass er ein Spiel finden kann.
Um ein Spiel zu erstellen, kann der Client erneut eine POST-Anfrage senden,
die auf die Games-Ressource oder URI verweist; diesmal muss im Anfragetext der
gewünschte Zustand der Ressource angegeben werden, der in diesem Beispiel nur den
Namen des Spiels enthält, aber auch weitere Eigenschaften umfassen könnte.
Der Server antwortet in der Regel mit dem Statuscode 201 Created,
falls der Ressourcen-Identifier im Anfragetext nicht angegeben wurde.
Die Antwort enthält es meist.
Um ein bestehendes Spiel zu aktualisieren.
Der Client sendet eine PUT-Anforderung mit derselben Ressource bzw.
derselben URI wie zum Abrufen eines Spiels, doch diesmal enthält
sie den Zustand der Ressource, ganz ähnlich dem POST-Szenario.
Diese Nutzlast wird den Zustand des Spiels, das mit einer bestimmten Kennung
verknüpft ist, vollständig ersetzen und wird typischerweise nur mit dem
Statuscode 204 No Content antworten.
Zuletzt sendet der Client eine zentrale Löschanfrage an die URI, die das
zu löschende Spiel identifiziert.
Nachdem die Ressource gelöscht wurde, antwortet der Server normalerweise
mit dem Statuscode 204 No Content.
Also kurz gesagt wird Ihre REST-API für Spiele so aussehen und den
Support liefern, den Ihre Kunden von modernem Backend erwarten.
Lassen Sie uns im Code schauen, wie man diese API in HV net core implementiert.
Bevor wir unsere Game-Store-REST-API implementieren,
Lassen Sie mich Ihnen zeigen, wie Sie mit Ihrer REST-API in VS Code
interagieren können, ohne dabei einen Browser verwenden zu müssen.
Und dazu installieren wir eine neue VS Code-Erweiterung.
Also gehen wir jetzt bitte in den Erweiterungsbereich von VS Code.
Und diesmal suchen wir nach REST Client, der hier drüben
ganz einfach zu finden ist.
Rest Client von wa MAO gehört zu den beliebtesten Erweiterungen,
um REST-APIs zu verwenden, auch wenn es nicht die einzige ist.
Es gibt viele davon.
Aber ich mag dieses hier, weil es so leicht zu bedienen ist.
Klicken wir auf Installieren.
Und jetzt gehen wir in unseren Dateiexplorer.
Lass uns das hier schließen.
Und wozu diese Erweiterung gut ist: Wir erstellen eine Datei, in der wir
Anfragen an unsere API definieren können.
Also klicken wir im Dateiexplorer erneut auf Game Store API.
Dann klicken wir auf Neue Datei.
Und lass uns der Datei den Namen 'games' geben, http.
Und hier können wir das Verb und den Ort des API-Endpunkts genau
definieren, den wir aufrufen möchten.
In unserem Fall haben wir derzeit, wie wir uns erinnern können, in Program
Cs unseren GET-Endpunkt an der Wurzel, der mit Hallo Welt antworten wird.
Richtig?
Also kehren wir nun zurück zu Games HGTP, was wir tun können, ist,
einen GET-Aufruf mit dem Ort unseres
Lokale Anwendung, die HTTP sein wird.
Schrägstrich Schrägstrich.
Und wie lautet der Standort?
Nun: Um sich daran zu erinnern, gehen Sie jederzeit in die Eigenschaften – Launch
Series bei Jason – und merken Sie sich, dass dieser Ort hier für Ihr HTTP-Profil
in der Anwendung vorgesehen ist.
Die hier genannte URL ist localhost und Port, bitte.
Also kopierst du das hier in Games, dieses HTTP-Ding dort drüben.
Und jetzt befinden wir uns in der Lage, unsere API direkt aus VS Code aufzurufen.
Nun, bevor wir dies tun, öffne ich mein Terminal, ich wechsle zur Game-Store-API,
und wir führen dotnet run aus.
Okay, ganz sicher.
Die Anwendung ist erfolgreich gestartet.
Beachte bitte, dass sie tatsächlich zuverlässig läuft,
und zwar am Port 51, 59.
Also legen wir jetzt los und klappen das hier ein wenig zusammen.
Und klicken wir hier, um zu sehen, was dort steht.
Anfrage senden.
Klicken wir dort.
Und wie du rechts siehst, klappe ich das jetzt zu.
Jetzt sehen wir alle Details der Antwort, die unsere Anwendung an
den Client zurückgeschickt hat, inklusive unseres Statuscodes.
Wir sehen den Statuscode zweihundert.
Okay.
Dort zurück.
Wir sehen den Inhaltstyp, der derzeit nur Text ist, und auch ein paar weitere Dinge.
Im Kern geht es um die eigentliche Antwort, die von unserer API zurückkommt.
Das ist eine deutlich bessere Art, über MVS-Code mit Ihrer API zu interagieren.
Dabei müssen Sie nicht ständig Browser öffnen.
Jetzt schließen wir das hier.
Schließen wir auch das.
Und verwenden wir außerdem die innere C#-Steuerung, um den Server zu stoppen.
Ich werde dieses Terminal vorerst beenden, und schauen wir uns unsere CS-Datei
an, um zu sehen, wie wir unseren ersten API-Endpunkt implementieren können.
Jetzt entferne ich diesen Breakpoint und öffne hier eine Zeile, um zu
beschreiben, welcher Art Endpunkt es ist, den wir implementieren werden.
Es handelt sich dabei um einen GET-Endpunkt, der zu jedem beliebigen
Zeitpunkt alle Spiele zurückgibt, die in unserer API verfügbar sind.
Und der eigentliche, exakte Ort, an dem diese Ressourcen künftig leben
werden, wird unter Games liegen.
Ich.
So teilt man ASP.NET Core mit, was zu tun ist, wenn eine HTTP-Anfrage in
unsere API kommt, durch MapGet-Methode, die wir hier definiert haben;
bisher reagiert sie nur darauf.
Zwei Zugriffe auf den Wurzelpfad der Anwendung, der hier auf
dieser Folie zu sehen ist.
Also wird der erste Parameter, den wir hier haben, das Muster sein, das durch
diese Map-Methode abgeglichen wird.
In unserem Fall möchten wir natürlich ändern, dass statt einfach auf die Wurzel
zu gehen das Muster Slash-Games sein soll.
Nun wird der zweite Parameter dieser Methode als der Handler bezeichnet.
Dies ist also der Handler, der dem Finnet-Kern mitteilt, was zu tun
ist, wenn eine Anfrage eintrifft und in dieses Muster passt, das
wir auf der linken Seite finden.
Ich.
Zu diesem Zeitpunkt sagt der Handler nur, dass wir den Hallo-Welt-String
an den Client zurückgeben wollen.
Natürlich wollen wir jetzt die Liste der Spiele, die von der
API verfügbar sind, zurückgeben.
Bevor wir die Liste der Spiele zurückgeben können, müssen wir eine
Darstellung dieser Spiele festlegen, die an den Client zurückgegeben wird.
Dafür müssen wir klären, was ein Data-Transfer-Objekt (DTO) ist.
Um unser DTO zu erstellen, gehen wir in unseren Solution Explorer.
Also öffnen wir den Solution Explorer jetzt wirklich.
Klappen wir es zu.
Klicken wir rechts auf Game Store API und erstellen einen ganz
neuen Ordner, den wir Dios nennen.
Dann klicken Sie mit der rechten Maustaste auf DTS und wählen Neue Datei.
Hier gibt es Optionen, um C#-TO zu erstellen.
Wir könnten dafür eine Klasse verwenden, doch ich bevorzuge hier einen Record-Typ.
Und das liegt daran, dass Datensätze sich gut eignen, Dinge zu zeigen.
Einfache Daten, die von Ort zu Ort wandern, ohne Änderung.
Und sie reduzieren Boilerplate-Code, typischerweise nötig bei Klassen.
Benennen wir den Datensatz erneut.
DTO ihi.
Eingeben.
Öffne es im Editor und mach das hier zu.
Lass mich jetzt meine Aktivitätsleiste ausblenden, damit wir hier ein wenig
mehr Platz bekommen, so wie hier nun.
Und nun ist die Frage, was hier in unser neues Spielvideo eingefügt werden soll.
Ich füge hier einen kurzen Kommentar ein; ADIO ist wirklich ein Vertrag
zwischen Client und Server, der eine gemeinsame Vereinbarung darüber
darstellt, wie diese Daten übertragen und verwendet werden sollen.
Im Wesentlichen möchten wir hier alle Eigenschaften genau auflisten, die wir
dem Client zurückgeben, wenn dieser unsere Liste der Spiele anfordert.
Nun gibt es Wege, Record-Typen in C# darzustellen.
Das Erste, was zu beachten ist: Man kann sie als Record-Klasse definieren
oder einfach 'record' sagen.
Es ist sozusagen ein Synonym der Record-Klasse, daher bleibt es einfach.
Außerdem lässt sich diese Eigenschaften hier in geschweiften Klammern definieren.
Aber einen einfachen Weg gibt es: APIs hier zu verwenden und
Eigenschaften direkt festzulegen.
Also schick ich das hier in die nächste Zeile und schließe es dort ab.
Und lass unsere erste Eigenschaft definieren: Die Kennung unseres
Spiels ist eine interne ID.
Sie ist die ID.
Der nächste Schritt wird der Name unseres Spiels sein.
Danach werden wir außerdem auch das Genre unseres Spiels festlegen.
Der Spielpreis wird voraussichtlich als klarer Preis im Dezimalformat
festgelegt, deutlich.
Und schließlich werden wir zusätzlich unser Veröffentlichungsdatum
angeben, das nur das Datum umfasst.
Damit ist unser erster DTO definiert, und wir können ihn jetzt auch schon ganz
sicher im neuen API-Endpunkt verwenden.
So schließen wir das hier – zurück zu Prod.-CS.
Bevor wir diese Spiele über den Endpunkt an den Client zurücksenden
können, benötigen wir eine Spielesammlung, um sie zurückzugeben.
Um es an dieser Stelle einfach zu halten, werden wir diese Ansammlung
von Spielen einfach als eine schlichte Liste darstellen, die wir direkt
hier in dieser Datei definieren.
Und später im Kurs werden wir sehen, wie man davon zu einer
echten Datenbank übergeht.
Also hier in Zeile fünf werde ich eine brandneue Liste von Game-DTOs definieren,
das ist unser neuer Typ, für den ich hier etwas ausführen muss, nur mit C#,
um meinen GameStore-API-DTO-Namensraum verwenden zu können.
Lass uns das als Spiele festlegen.
Okay, also hier legen wir unser erstes Spiel fest.
Ich scrolle ein wenig nach unten.
Lass uns es neu definieren.
Spiel mit Idee Nummer 1.
Der Name wird letztendlich State Fighter zwei heißen.
Das Geschlecht wird beim Kämpfen beteiligt sein.
Der Preis wird neunzehn neunundneunzig betragen.
Und das Datum wird künftig nur ein neues Datum sein, das eindeutig
dem Jahr 1992 zugeordnet ist.
Monat sieben, und der Tag fünfzehn.
Und ich schicke das auf die nächste Folie, damit wir es hier wirklich besser sehen.
Und wir sehen, dass dort der Preis ein Problem ist.
Und das ist der Grund.
Der Compiler wird bei dieser Zahl leicht verwirrt.
Er weiß nicht, ob wir hier Double- oder Dezimalzahl verwenden.
Da wir das nun als Dezimalzahl festlegen, hilft dem Compiler, indem wir hier
einfach den Buchstaben M hinzufügen, und das zeigt, dass wir die Zahl
als Dezimalzahl verwenden möchten.
Jetzt ist es wohl besser, nicht nur mit einem Spiel zu
arbeiten, sondern mit mehreren.
Noch ein paar weitere Spiele.
Ich füge aus der Zwischenablage hier ein.
Okay, also haben wir nicht nur eins, sondern drei Spiele.
Wir haben unser zweites Spiel.
Es wird Final Fantasy, sieben Revert, RPG.
Hier der Preis und das Datum.
Zuletzt haben wir unser After-Bot-Spiel.
Das dritte Spiel wird Plattform-Spiel sein.
Hier Preis und Veröffentlichungsdatum.
Wie gesagt, verwenden wir im ersten Teil dieses Kurses diese Spiel-Liste,
indem wir einfach eine Merkliste von Spielen hinzufügen, und später
wechseln wir zu einer echten Datenbank.
Jetzt, wie verwenden wir diese Spiel-Liste denn mit unserem API-Endpunkt?
Nun scrollen wir ein wenig nach unten.
Wir müssen nur unseren Handler aktualisieren.
Hier ist ein langer Ausdruck, um es ihm mitzuteilen, dass wir
nicht mehr zurückkehren möchten.
Hallo Welt, stattdessen geben wir unsere Spieleliste so zurück.
Es gibt hier viele Wege, deinen Handler zu definieren; einer der einfachsten.
Jetzt führen wir die Anwendung aus und sehen, was passiert, wenn wir
unseren neuen Spiele-Endpunkt aufrufen.
Ich öffne hier mein Terminal.
Ich wechsle zum Game Store API.
Nochmal führe ich es nun aus.
Okay, es läuft.
Schließe das Terminal kurz, dann kehre ich zum Datei-Explorer zurück.
Ich drücke Strg, Umschalt und E, um meinen Explorer zu öffnen.
Sehr schnell wechsle ich kurz in den Datei-Explorer, nicht
in den Lösungs-Explorer.
Ich öffne die HTTP-Datei.
Ich modifiziere die hier vorliegende Anfrage geringfügig, damit sie auf
unseren Games-Endpunkt verweist.
Denk daran, dass unser Endpunkt jetzt unter /games liegt;
daher kopiere ich ihn auch.
Ich füge ihn hierhin direkt nach dem Host-Import ein.
Und nunmehr sind wir bereit, unseren Games-Endpunkt aufzurufen.
Also klicken wir hier, um eine Anfrage zu senden, und auf der rechten Seite
sehen wir unseren Statuscode 200.
Okay.
Dies war eine erfolgreiche Antwort.
Dieses Mal erhalten wir den Inhaltstyp application/json, weil wir jetzt eine
Sammlung von Objekten zurückgeben, die standardmäßig von ASP.NET Core in eine
JSON-Antwort transformiert werden kann.
Und hier unten können wir die JSON-Antwort sehen.
Be achten Sie ja, dass dies ein Array ist, in dem jedes Element eines unserer
Gewinne sein wird; wir speichern es vorerst in unserer API im Speicher.
Hier sind Spiel eins, zwei und drei.
Unser erster Endpunkt läuft wie erwartet.
Nun schauen wir, wie wir diesmal einen zweiten Endpunkt einbauen,
um nur ein Spiel abzurufen statt der Liste der Spiele.
Dazu schließen wir das.
Also stoppen wir unseren Server.
Ich drücke hier Strg+C, schließe das Terminal und
kehre zum Programm C# S zurück.
Für unseren neuen Endpunkt verwenden wir dieselbe Idee wie beim ersten.
Wir fügen hier ein paar Zeilen hinzu.
Wir fügen etwas Dokumentation hinzu.
Das ist wirklich optional.
Ich mache das gern, damit ich genau weiß, was ich von diesem Endpunkt erwarten kann.
Dieser Endpunkt zielt erneut auf das Gamepad, und am
Ende geben wir die Route an.
Die Spiel-ID, die wirklich abgerufen werden soll.
Wenn du Nummer Eins abrufen willst, geben wir hier die Eins durch.
So ist der korrekte Weg, RESTful Weg, um eine Ressource über ihre
eindeutige Kennung abzurufen.
Also, um das umzusetzen, erstellen wir eine komplette App
für diesen gegenwärtigen Markt.
Wir beginnen mit demselben Pfad, also dem Pfad /games, aber diesmal
müssen wir die eindeutige ID angeben.
Und dazu fügen wir hier noch einen weiteren Slash ein, und wir
öffnen und schließen geschweifte Klammern, und hier fügen wir den
Namen der Eigenschaft ein, die diese eingehende ID repräsentieren soll.
und es zu nutzen.
Was wir tun werden, ist, unseren zweiten Parameter hinzuzufügen, der, wie Sie
wissen, den Handler darstellen wird.
Für diese Methode beginnen wir erneut mit der Klammer, doch dieser Abschnitt
bietet uns die Gelegenheit, die ID des eingehenden Parameters zu definieren.
Also in diesem speziellen Fall erhalten wir eine ID, die exakt dem Namen
dieses Parameters entspricht, richtig?
Es ist wirklich genau diese ID.
Und dann müssen wir erneut festlegen, welche Logik ausgeführt werden muss,
wenn eine Anfrage mit genau diesem Muster eingeht, das wir hier definiert haben.
Also in diesem Fall beginnen wir damit, unsere Spielesammlung zu
durchsuchen, doch diesmal müssen wir das passende Spiel finden.
Einfacher Weg, das zu tun, ist die Find-Methode zu verwenden.
Wir finden also das Spiel und sagen, dass wir es abrufen möchten, bei dem
game.id der als Parameter übergebene ID-Wert entspricht, und das ist
wirklich alles, was wir tun müssen.
Beachten Sie: PN Net Core ist klug und versteht, dass wir hier einen Parameter
ID erhalten, er erwartet ja, dass diese ID Teil der Route hierher kommt.
Jetzt starten wir unseren Server, damit wir unseren neuen Endpunkt testen können.
Also öffne ich mein Terminal, STRG-J.
Dotnet ausführen.
Okay, die App läuft nun.
Ich schließe das Terminal; Gains dot HTTP.
Wir definieren hier einen neuen Endpunkt oder eine neue Anfrage,
indem wir sie durch die Raute trennen.
Wir müssen drei Rauten setzen, und nun versteht es gut, dass das, was
wir hier haben, eine neue Anfrage ist.
Diese Anfrage wird im Wesentlichen dieselbe sein wie die vorherige.
Ich kopiere es jetzt hier.
Und der Unterschied ist, dass ich am Ende ein bestimmtes Spiel anfordern werde.
Nehmen wir Spiel Eins, bitte.
Klicken wir auf 'Anfrage senden'.
Und tatsächlich erhalten wir rechts erneut eine hundertprozentig
erfolgreiche Antwort.
Okay, App Jason O. Und diesmal sehen wir hier unten Folgendes.
Die Antwort, die unserem Spiel Nummer eins entspricht.
Großartig.
Jetzt wissen wir, wie man die komplette Spieleliste abruft und
wie man ein einzelnes Spiel erhält.
Aber was, wenn man ein neues Spiel in unsere Sammlung aufnehmen möchte,
das einer POST-Anfrage entspricht.
Sehen wir uns an, wie das umgesetzt wird.
Schließen wir das hier, Strg-J bitte.
Ich stoppe den Server mit Strg-C#.
Zurück in S.
Lass uns ein wenig nach unten scrollen, und erneut definieren wir
einen neuen Endpunkt, für unsere API.
Jetzt wird es sich um einen POST-Endpunkt handeln, der erneut
auf unsere Spielroute abzielt.
Bevor wir es tatsächlich implementieren, benötigen wir hier ein brandneues
Datentransferobjekt (DTO), das die eingehende Nutzlast für das
Spiel repräsentiert, das wir in unserer REST-API erstellen möchten.
Also erstellen wir zuerst dieses DTO und danach hierher zurück, um
den Endpunkt zu implementieren.
Dann öffne ich Strg+Umschalt+E, um den Explorer zu öffnen, und wechsle
wieder in den Solution Explorer.
Lass uns erneut auf die DTS-Datei klicken, bitte.
Es wird noch ein Datensatztyp sein.
Und nennen wir diesen hier bitte.
Erstelle bitte ein Spiel, TTO.
Ich klicke nur auf die Datei, klappe zu.
Wie gesagt müssen wir Record nicht nutzen.
Es kann auch einfach ein Record sein.
Das reicht völlig aus.
Wir wechseln erneut zur anderen Syntax mit Klammern, in denen wir
festlegen, welche Eigenschaften wir von unserem Client erhalten sollen.
In diesem Fall beginnen wir mit dem Namen.
Wir fangen nicht mit der ID an, weil die ID gewöhnlich vom Server
erzeugt und bereitgestellt wird.
Nachdem die Ressource erstellt wurde, erhält man die ID in der
Regel nicht direkt vom Client, daher verwenden wir einfach den Namen.
Wir verwenden den generischen Spielbegriff.
Die C# ML Price Rise Rise, und dann nur unser Veröffentlichungsdatum.
Und das ist alles, was wir fürs neue DTO brauchen.
Also schließen wir das und kehren zum Cs-Programm zurück, um unseren
POST-Endpunkt zu implementieren.
Diesmal bauen wir eine App, die POST abbildet.
Es gibt viele MAP-Varianten, die wir nutzen können.
POST ist ja die richtige Wahl für diesen Fall.
Wir fangen mit unserer Spiele-Route an.
Und dann legen wir fest, was genau unser neuer, künftiger
Handler sein wird, in der Praxis.
Jetzt, hier in den Klammern, werden wir genau die Instanz des
Create-Game-DTO empfangen, die wir soeben implementiert haben.
Also empfangen wir dieses Create-Game-DTO, welches sich auf ein
neues Spiel bezieht – nennen wir es so.
Lass uns hier unseren Lambda-Ausdruck öffnen, um den Leib festzulegen.
Noch einmal: Beachten Sie, wie ASP.NET Core hier wirklich ziemlich klug vorgeht,
sodass es den Body erkennt, den wir von unseren Spielen aus senden werden,
diese HTTP-Datei, die unser Client ist und die angepasst werden muss.
In dieses Objekt hier, das wir 'new name' nennen.
Und in diesem Fall, da unsere Spielesammlung im Speicher abgelegt
ist, in dieser Liste, von der wir hier wissen, dass wir sie haben,
möchten wir einfach nur eine brandneue Instanz von Game-DTO erstellen und
dieses Spiel in diese Liste einfügen.
Dafür scrollen wir nach unten.
Definieren wir unser Spiel.
DTO-Spiel neu.
Schließen wir das.
Und hier geht es darum, die ID zu definieren.
Das ist die erste Eigenschaft.
Also für die ID verwenden wir einfach 'games.count + 1'.
Damit wird die ID für den Namen festgelegt.
Wir haben 'new game.name'.
Neues Spiel.
Neues Spiel, lege den Preis des neuen Spiels fest.
Und beim neuen Spiel lege außerdem das Veröffentlichungsdatum fest.
Okay, unser neues Spiel ist dort bereit.
Jetzt fügen wir es unserer Liste hinzu.
Also Spiele, die das Spiel hinzufügen, und zuletzt müssen wir
dem Client noch etwas zurückgeben.
Und hier gilt die Konvention für eine ordnungsgemäße REST-API darin,
eine 201-Antwort zurückzugeben, was bedeutet, dass das Spiel erstellt
wurde, und in der Regel möchte man auch die Nutzlast zurückgeben.
Von der erstellten Ressource.
Jetzt, da wir es auf die folgende Weise tun können, mit dem, was wir
gleich sagen werden, ergeben sich Ergebnisse, die eine Route erzeugt haben.
Es gibt mehrere Möglichkeiten, dies zu tun.
Und für den ersten Parameter hier geben wir den Namen der Route an, die
der Client verwenden kann, um auf die gerade erstellte Ressource zuzugreifen.
Was ist das für eine Route?
Die Route wird hier oben sein, oder?
Hier ist sie.
Dieser hier, das Kartenkit.
Aber wir haben der Route noch keinen Namen gegeben, was optional ist, aber
in diesem Fall brauchen wir ihn, damit der POST-Endpunkt diese Route versteht,
damit er die richtige URL erzeugt, damit der Client zugreifen kann.
Dafür müssen wir hier unter Map Gate einfach einen Aufruf verketten; wir werden
einen Aufruf mit Namen verketten, und hier weisen wir diesem Pfad einen Namen zu.
In diesem Fall benennen wir ihn in der Tat einfach 'it game'.
Und jetzt haben wir eine Möglichkeit, von anderen Endpunkten aus
auf diesen Pfad zu verweisen.
Also lasse ich es einfach kopieren, das Game zurück ans Ende unseres
Map-Posts bringen, und ich werde es hier hinein einfügen, wirklich.
Das ist dritter Parameter.
2. Parameter.
Es wird die eindeutige Kennung des neu erstellten Spiels sein,
die Teil der Get-Spielroute ist.
Denk daran, dass die andere Route eine ID erhält.
Sie erhält eine ID.
Deshalb müssen wir sie als Parameter in MAP-Post eintragen,
um die Route abzuschließen.
Dafür verwenden wir einen anonymen Typ.
Also setzen wir die neue ID gleich der Spiel-ID.
Und als letzten Parameter möchten wir die Payload bzw.
den Body der Ressource angeben, die gerade erstellt wurde.
Das wird also unser Spiel sein.
Jetzt ist hier eine gute Praxis darin, denselben String nicht mehrfach in
der Anwendung zu hartkodieren; aber im Moment haben wir Get Game und
definieren ihn hier im POST-Endpunkt.
Außerdem haben wir ihn hier im Get By ID-Endpunkt definiert.
Wir können ihn in eine kleine Konstante refaktorisieren, die wir
an beiden Stellen verwenden können.
Also klicke ich hier auf die Lampe, um Refactorings zu sehen.
Und ich wähle das Refactoring "Introduce constant" aus.
Ich wähle "Introduce local constant" für GI game aus.
Und der Endpunktname wurde der Konstante gegeben, und sie verwendet
ihn hier gerade unter diesem Namen.
Jetzt geben wir ihr einen besseren Namen.
Also drücke ich hier F2, um diese Konstante in Sinnvolles umzubenennen.
Nennen wir sie Get Game-Endpunktname.
Gib ein.
Nun haben wir wirklich einen besseren Namen für die Konstante.
Außerdem will ich diese Konstanten oben in der Datei wirklich haben,
nicht in der Mitte der Anwendung.
Also schneide ich das einfach raus.
Ich geh ganz nach oben und definiere es schon vorher.
Unser Builder-Objekt.
Gleich nach unserer Using-Direktive dort.
Also das ist unsere Konstante, und nun können wir dieselbe Konstante nutzen.
Ich werde sie einfach kopieren und hier unten für unseren POST-Endpunkt verwenden.
Dort.
Also haben wir jetzt unseren POST-Endpunkt fertig, und wir können ihn über
unsere Gains.http-Datei ausprobieren.
Also starten wir unseren Server.
Nochmals öffne ich mein Terminal.
Äh, wir führen den Start durch.
Okay, der Server läuft jetzt.
Schließe das hier, kehre zurück zu gains dot TP.
Was wir tun möchten, ist wirklich eine brandneue Anfrage einzuleiten.
Dann nehmen wir drei Pfund.
Lass uns festlegen, dass dies ein Beitrag ist, oder?
Also beginnen wir mit dem Beitrag.
Die Route bleibt im Wesentlichen dieselbe, daher kopiere ich sie
hierher, aber diesmal müssen wir ein paar neue Dinge tun.
Zuerst müssen wir wirklich festlegen, welcher Inhaltstyp für
diesen Beitrag verwendet wird.
In diesem Fall wird nun der Inhaltstyp application/json sein.
Und dann müssen wir definieren, was der Body der Anfrage sein
wird, um sie zu begleiten.
Beachte, hier muss eine leere Zeile stehen, damit es funktioniert.
Die neunte Zeile bleibt leer; in Zeile 10 fügen wir den Body ein.
Hier verwenden wir korrekte JSON-Syntax.
Wir beginnen mit vierteljährlichen Gehaltserhöhungen und liefern danach alle
Eigenschaften, die wir im DTO definieren.
Erinnere dich daran, dass wir zu Contra Shift E zurück in unseren Game-Store
DTS gehen und ein Game-DTO erstellen.
Wir haben wirklich festgelegt, dass wir einen Namen angeben,
Preis und Veröffentlichungsdatum generieren müssen, daher müssen
wir all das als Teil davon liefern.
Jason.
Payload, also schließe das.
Definieren wir unseren Namen.
In diesem Fall wird es, sagen wir, Super Mario Bros Wonder sein.
Fantastic Game Generate wird ein Plattformspiel sein.
Danach haben wir unseren Preis bereits festgelegt.
Es wird voraussichtlich 59,99 kosten.
Und danach folgt das Veröffentlichungsdatum endgültig,
Was der 20.10.2023 sein wird.
Okay.
Also das ist alles, was wir tun müssen.
Jetzt klicken wir auf Anfrage senden, um dieses Spiel in unserer API zu erstellen.
Also klicken wir darauf, und auf der rechten Seite können wir
sehen, dass der erwartete 201 Created-Status erhalten wurde.
Okay?
Das bedeutet, dass die Ressource in der RES-API erstellt wurde, und unten hier
können wir die Antwort sehen, die wir von dieser Erstellung erhalten haben.
Hier drüben ist eine Antwort, die die nagelneue ID der gerade
erstellten Ressource enthält.
Und nicht nur das: Wir haben diesmal auch das, was man ganz allgemein als
Location-Header bezeichnet, dort drüben.
Wir erhalten das, weil wir es wirklich verwenden; die Created-At-Route-Methode
ist klug genug zu verstehen, wohin der Client gehen kann, um nach der
gerade erstellten Ressource zu suchen.
Wie dort steht, können wir zu diesem Ort gehen, um die
brandneue Ressource abzurufen.
Also kannst du fortfahren und das kopieren.
Also lass uns das einfach kopieren, und wir können hier zurück zu
unserem Get By ID-Bereich wechseln.
Wir können einfach diesen gesamten Text durch den anderen String ersetzen.
Klicke auf 'Anfrage senden', und nun können wir erneut das Super
Mario Bros. Wonder-Spiel abrufen.
Prima.
Wir haben Endpunkte zum Abrufen und Erstellen von Ressourcen.
Jetzt soll ein Endpunkt zum Aktualisieren einer bestehenden
Ressource erstellt werden.
Also lass uns schließen.
Ich werde meinen Server erneut stoppen.
Schließe es in Program.cs.
Lass uns mal noch ein wenig nach unten scrollen, und hier werden wir
unseren brandneuen Endpunkt definieren, der ein PUT-Endpunkt sein wird.
Das wird, wie gesagt, unsere Spiele-Route anvisieren, aber das muss auch die ID des
zu aktualisierenden Spiels einschließen.
Also wenn Sie Spiel Nummer Eins aktualisieren wollten, müssen wir dort
die Nummer Eins einschließen und dann den Body der POST-Anforderung angeben.
Jetzt,
Genau wie wir es mit unserem POST-Endpunkt gemacht haben, müssen wir hier festlegen,
wie die Form der Nutzlast aussieht, die wir an unseren PUT-Endpunkt senden sollen.
Dafür brauchen wir ein TTO.
Also verwenden wir Control Sheet E, um zu unserem Explorer zu gelangen.
Wechseln wir zum Solution Explorer.
Lass uns mit der rechten Maustaste auf die neue DTS-Datei klicken.
Wähle Aufnahme aus und benenne diese hier.
Aktualisiere Spiel-DTO.
Eingeben.
Klicke nun auf Update-Spiel-DTO und falte dieses hier sauber zusammen, bitte.
Ich.
Lass uns der Richtlinie der anderen DTS folgen, indem wir
hier keine Klasse einfügen.
Es ist absolut dasselbe.
Public Record Update-Spiel, DTO.
Lass uns hier noch ganz gezielt auch in die Klammer-Syntax wechseln.
Und jetzt hier führen wir die Eigenschaften ein, die wir in
diesem Endpunkt erhalten werden.
Also erneut: Das wird unser Name und unser Geschlecht sein.
Nur unser Dezimalpreis und unser Datum, nämlich das Veröffentlichungsdatum.
Und jetzt, da wir unser DT schon haben, gehen wir erneut hinein.
Problem C# S, und lasst uns den neuen Endpunkt implementieren.
Also für diesen hier werden wir eine App-Map erstellen, hinzufügen.
Das Muster wird wieder genau so sein, wie es bei Slash-Spielen festgelegt war.
Wir müssen die ID erhalten.
Also führen wir hier die ID ein.
Und dann definieren wir unseren Lambda-Ausdruck.
Lassen Sie mich hier an dieser Stelle den Körper vorbereiten, und damit beginnen
wir sogleich damit, alles Notwendige auszuarbeiten, das benötigt wird.
Nun müssen wir in diesem Fall zwei Parameter in unseren
Lambda-Ausdruck übernehmen.
Der erste Parameter wird natürlich die ID sein, also welches
Spiel aktualisiert werden soll.
Also verwenden wir die ID und den zweiten Parameter.
Also gut, die Nutzlast.
Die Nutzlast des Spiels, das wir aktualisieren müssen.
Also für diesen Fall aktualisieren wir das Spiel-DTO.
Aktualisiertes Spiel.
Nochmals: ASP.NET Core wird klug sein und auch verstehen, dass erster
Parameter direkt aus der Route kommt, während zweiter Parameter
aus dem Anfragetkörper kommt.
Was wird hier die Logik fürs Update sein?
Nun, das Erste, was zu tun ist, ist.
Finde das Spiel, das wir aktualisieren müssen.
Also machen wir Folgendes.
Nehmen wir Bar-Index.
Es geht um Spiele.
Finde den Index des Spiels, bei dem game.id dem übergebenen
ID-Parameter entspricht.
Okay, das wird uns also den Index geben.
Und basieren wir jetzt auf diesem Index.
Wir können dann das Element in unserer Sammlung aktualisieren,
das dem Index entspricht.
Also, wir werden jetzt wirklich sagen, dass der Spiele-Unterindex
dem neuen noch frischen Spielvideo wirklich ganz exakt gleich ist.
Das wird als erste Eigenschaft die ID haben, die einfach
eine bereitgestellte ID ist.
Und dann werden wir das aktualisierte Spiel.Name, das aktualisierte Spiel,
das erneut aktualisierte Spiel, den Preis und das Veröffentlichungsdatum
des aktualisierten Spiels haben.
Okay, das wird wirklich alle Eigenschaften unseres bestehenden Spiels aktualisieren.
Und schließlich geben wir gemäß einer guten Konvention in REST-APIs Ergebnisse
zurück, die keinen Inhalt enthalten.
Und das ist ja so ziemlich alles.
So implementierst du diese Version unseres PUT-Endpunkts.
Jetzt testen wir es mal.
Ich starte meinen Server jetzt erneut.
Ich führe im Terminal net run heute aus.
Okay.
Ich schließe das wieder zu Games.
Bei HGTP legen wir hier gleich einen neuen Abschnitt fest.
Scrolle jetzt nach unten, ich mache drei Pfund.
Das wird wieder an denselben Ort zurückgesetzt.
Also werden wir das alles tun.
Ich werde das hier einfügen
Wie gesagt, müssen wir festlegen, welche ID dem Spiel gehört, das jetzt
aktualisiert werden soll, damit wir uns an unsere Ideen erinnern können.
Wir können die vollständige Liste der Spiele über unsere erste Anfrage abrufen.
Also klicken wir auf Anfrage senden.
Hier sind unsere drei Spiele.
Wir werden unser Three Fighter 2-Spiel aktualisieren.
Vielleicht werden wir die Namen etwas verändern, und den Preis verändern.
Also wird dies Spiel Nummer Eins wirklich sein.
Um die Dinge einfach zu halten, damit es übersichtlich bleibt.
Ich kopiere das hier, Jason.
Auch das kopiere ich.
Die Idee ist also, dass ich die ID in die Route aufnehme und
dort ein Leerzeichen freilasse.
Ich füge dort ein, was ich gerade kopiert habe.
Lass uns das dort besser abstimmen und dann.
Der Hauptunterschied hier ist, dass wir die ID nicht benötigen,
da sie Teil der Route ist.
Wir können das entfernen; dann müssen wir festlegen, welche
Änderungen eingeführt werden.
Nun wird es jetzt ein Street Fighter.
Topo ist eine Variante des Spiels, und zum Preis ist es im Angebot.
So nun entfernen wir sie, damit der Preis neun Komma neunundneunzig ist.
Vergiss nicht, hier mal auch festzulegen, was der Inhaltstyp sein wird.
Also wird der Inhaltstyp application, JSON, sein, genauso
wie wir es mit POST gemacht haben.
Also klicken wir jetzt gemeinsam auf 'Anfrage senden'.
Und wie erwartet haben wir unsere 204 No Content-Antwort erhalten, was
bedeutet, dass dies ein Erfolg war.
Eine erfolgreiche Anfrage, und wir können natürlich bestätigen, dass
das Spiel durch einfaches erneutes Abfragen desselben Spiels über unsere
Abfrage nach der ID aktualisiert wurde.
Also werde ich das auf Eins umstellen, dieselbe Abfrage erneut ausführen,
und tatsächlich können wir bestätigen, dass das Spiel umbenannt wurde.
Es ist ein strenger Kämpfer zu Turbo.
Der Preis hat sich geändert.
So war das Update gut, ja.
Eine Sache ist bei diesem Update oder Endpunkt zu beachten.
Also halte ich den Server bitte kurz an.
Gehen wir zurück zu Pro Cs.
Und es könnte auch mehrere PUT-Anfragen an unsere API geben, die dieselbe
Änderung gleichzeitig auslösen.
Was hier prinzipiell möglich ist, ist, dass die Spieleliste hier
eine statische Liste ist, richtig?
Und wenn mehrere Threads gleichzeitig darauf zugreifen und sie verändern,
könnte das natürlich zu ernsthaften Dateninkonsistenzen führen.
Also für eine Produktionsanwendung ist eine solche Liste keine gute Option.
Du willst etwas anderes verwenden, vielleicht ein paralleles
Backup oder Ähnliches, das sicher gegen Bedrohungen ist.
Wir stehen an einem Wendepunkt und lernen, wie wir unsere beste API
erstellen und die Kursstruktur aufbauen.
Wir wechseln zu einer ordentlichen Datenbank und entfernen
diese Liste vollständig.
Stopp.
Beachte das, falls du es bitte in die Produktion bringst.
Nun werfen wir einen Blick darauf, wie wir unseren letzten Endpunkt implementieren,
also unseren Lösch-Endpunkt.
Und dazu scrollen wir hier langsam nach unten.
Lassen Sie uns einen neuen Abschnitt vor oder nach dem Lauf einfügen.
Und das wird ein Löschaufruf an die Spiele sein.
Und erneut wird er die ID des zu löschenden Spiels empfangen.
Sagen wir, es wird Spiel Nummer eins sein.
So würden wir eben den Endpunkt aufrufen.
Nun, glücklicherweise benötigt der Lösch-Endpunktsystem keine DTS, da er nur
die ID des zu löschenden Spiels empfängt.
Er wird keine Payload zurückgeben.
Also können wir unseren Endpunkt sofort definieren.
Wir werden 'up that map, delete' sagen.
Wir definieren hier das Pad.
Spiele, bei denen wir DID bitte angeben müssen,
Und dann definieren wir unseren Landausdruck, und erhalten die ID.
Lass uns Körper definieren.
Und da der Zweck dieses Endpunkts darin besteht, das Spiel zu löschen,
das der entsprechenden Kennung entspricht, können wir wirklich einfach
von 'games dot removal' sprechen.
I. An der Stelle, an der sich das Spiel befindet, ist das Spiel mit
der ID, die der übergebenen ID entspricht, ein wirklich einfacher
Weg, das Spiel zu entfernen.
Und dann werden wir erneut mit Ergebnissen antworten, die keinen Inhalt enthalten,
was die allgemein gültige Konvention für ordnungsgemäß aufgebaute REST-APIs ist.
Beachten Sie bitte, dass es in der API egal ist, ob das Spiel existiert
oder nicht; die Konvention für einen Lösch-Endpunkt ist, dass nachdem der
Endpunkt die Anfrage empfangen und verarbeitet hat, die Ressource nicht
mehr existieren sollte – egal, ob sie vorher existierte oder nicht.
Aus diesem Grund prüfen wir nicht einmal, ob das Spiel existiert.
Wir entfernen einfach Instanzen des Spiels, deren ID gegeben ist.
Okay, also lasst uns diesen neuen Endpunkt testen, indem wir unseren
Server erneut starten, dot run.
Lass uns über HTTP in unsere Spiele wechseln.
Hier fügen wir einen extra Eintrag hinzu.
Dreifache Pfunde.
Lasst uns bitte löschen.
Kopiert und fügt bitte unseren Pfad vom PUT-Endpunkt ein, und
lasst uns dabei sagen, dass wir tatsächlich löschen werden, ja?
Unser allererstes Spiel, Nummer eins.
Zuerst sollten wir bestätigen, was die vollständige Liste der Spiele ist,
bevor wir die Löschung durchführen.
Klicken wir hier bitte auf unsere erste Anfrage.
Wir haben Spiele eins, zwei und drei.
Jetzt legen wir los und führen die Löschanfrage aus.
Wir senden die Anfrage.
Wir erhalten 204 No Content, was bedeutet, dass es ein Erfolg war.
Dieses Spiel darf nicht mehr existieren.
Wenn du erneut hineingehst, lass uns bei der ersten Abfrage die
vollständige Liste der Spiele abrufen.
Und wie man sieht, ist Spiel Nummer eins leider verschwunden.
Es ist hier nicht mehr verfügbar.
Wie gesagt, könnten wir denselben Endpunkt erneut mit Nummer eins
aufrufen, auch wenn er nicht existiert.
Wir können dieselbe Anfrage erneut senden.
Und erneut erhalten wir 204 No Content, weil der Client nicht wissen muss, ob
das Spiel vorher bestand oder nicht.
Die Richtlinie lautet: Ressource existiert nach dem Endpunkt nicht mehr.
Eine Sache, die Sie sich vielleicht fragen, ist, was passiert,
wenn wir versuchen, ein Spiel abzurufen, das nicht existiert.
Was passiert also, wenn wir unseren ID-Endpunkt hier verwenden, aber die Idee
eines Spiels, das einfach nicht da ist.
Nun, probieren wir es aus und sehen, was passiert.
Starten wir unseren Server erneut.
Gehen wir zu den Spielen bei http, und diesmal versuchen wir
das Spiel Nummer fünf abzurufen, das überhaupt nicht existiert.
Klicken wir auf Anfrage senden.
Und wie Sie sehen können, ist ihre Antwort wirklich etwas unerwartet, richtig?
Also erhalten wir erneut eine 200er-Antwort, okay?
Was schon bedeutet, dass es kein Erfolg ist.
Wir können das Spiel nicht finden, und wirklich schlimmer, hier erhalten wir
ebenfalls einen neuen Wert, oder wir geben hier einen neuen Wert zurück.
Die Risikoleitlinien sagen ausdrücklich, dass, falls die Ressource nicht
vorhanden ist, man etwas zurückgibt.
Äh, keine Antwort gefunden.
Lass uns das richten.
Schließen wir das hier.
Lass den Server stoppen.
Lass uns Cs wieder programmieren.
Folgendes tun wir.
Wir kehren zu unserer Abfrage nach ID zurück.
Lass uns damit beginnen, ihm einen passenden Körper zu geben.
Ich öffne hier und schließe vierteljährliche Klammern.
Ich bringe es hinein.
Unsere vierteljährlichen Klammern sehen so aus.
Und dann möchte ich tatsächlich das Endergebnis unserer Spiele registrieren,
die den Find-Aufruf auslösen, damit wir überprüfen können, ob wir das
Spiel überhaupt finden konnten.
Also werden wir sagen, dass unser Spiel dem entspricht, was Find-Aufrufe bewirken;
lassen wir das kurz festlegen, und dann.
Was wir tun können, ist Folgendes,
Da unsere Spielvariable hier wirklich dauerhaft erneuerbar sein wird.
Beachten Sie hier bitte das Fragezeichen.
Das bedeutet, dass es wirklich durchaus neu sein könnte; also sagen wir, dass
wir zurückgeben, falls das Spiel neu ist.
Falls es neu ist, geben wir tatsächlich Ergebnisse zurück, die
nicht gefunden werden, was die logisch erwartete Antwort ist, wenn die
Ressource nicht gefunden werden kann.
Und ansonsten beabsichtigen wir wirklich einfach, Ergebnisse
zurückzugeben, die in Ordnung sind, einschließlich unseres Spielobjekts dort.
Und das sollte reichen, um die richtige Antwort zu geben, je
nachdem, ob das Spiel existiert.
Also probieren wir das jetzt mal aus.
Lass uns unseren Server neu starten.
Lass uns Spiele über HTTP aufrufen, und erneut versuchen,
Spiel Nummer fünf abzurufen.
Mal sehen, was passiert.
Senden wir eine Anfrage, und tatsächlich erhalten wir jetzt den 404 Not Found.
Es gibt hier keine Antwort, und das zeigt dem Client eindeutig darauf hin, dass die
Ressource wirklich nicht vorhanden ist.
Nun sollten wir auch unseren PUT-Endpunkt ähnlich behandeln, oder?
Denn auch das wird versuchen, diese Ressource zu lokalisieren.
Also scrollen wir hier nach unten zu meinem PUT-Endpunkt.
Und hier, direkt nachdem wir den Index des Spiels gefunden haben,
werden wir sagen, dass der Index -1 ist, falls diese Bedingung zutrifft.
Was bedeutet, dass wir den Index des angefragten Spiels in diesem
Zusammenhang nicht finden konnten.
Wir geben einfach Ergebnisse zurück, die in dieser Situation nicht gefunden wurden.
Jetzt ist der Fakt, dass wir 'nicht gefunden' zurückgeben, wenn wir die
Ressource nicht finden können, eine polemische Aussage, denn manche sagen,
man solle stattdessen ganz einfach die Ressource erstellen, falls sie nicht
gefunden wird, um die Anforderungen einer POST-Anfrage zu erfüllen.
Jetzt gibt es keine klare Antwort dazu.
Und im Rahmen dieses Kurses wähle ich einfach den vorhandenen Noten-Ansatz.
Also testen wir das kurz.
Wir prüfen, ob es klappt, wie erwartet.
Also starten wir unseren Server.
Wir gehen zum PUT-Endpunkt.
Wir versuchen es erneut; Spiel Nummer fünf existiert nicht.
Gleiche Anfrage.
Und wie vermutet, erhalten wir endlich eine Nicht gefunden-Antwort.
Nun, eine Sache, die Sie jetzt beunruhigt, ist, wie viel Code wir in
dieser CS-Datei des Programms haben.
Denn wenn wir so weitermachen, wird es immer schwieriger, Dinge in der
Datei zu finden und schnell Änderungen vorzunehmen, oder nicht wahr?
Das ist also wirklich keine gute Praxis, ja, klar.
Also können wir alle diese Endpunkte, die wir bisher im C#-Programm deklariert
haben, einfach in eine brandneue Klasse verschieben, die speziell dazu entworfen
ist, die Endpunkte zu definieren.
Und damit wird uns außerdem eine besonders leicht verständliche, äußerst bequeme
Methode ermöglichen, alle Endpunkte auf einmal zuverlässig zuzuordnen.
Dazu gehen wir zurück in den Lösungs-Explorer.
Also Kontrast Shift-E.
Hier sind wir im Social Explorer,
Und legen wir zuerst einen neuen Ordner für unsere Endpoints an.
Klicken wir mit der rechten Maustaste auf Game Store API.
Wir erstellen einen neuen Ordner.
Wir nennen ihn Endpoints.
Dann erstellen wir in diesem Ordner eine Klasse.
Also klicken wir erneut mit der rechten Maustaste auf Endpoints.
Eine Datei wird eine Klasse sein.
Benennen wir Games Endpoints.
Geh rein.
Lass uns zu den Endpunkten des Spiels gehen, CS jetzt.
Jetzt lösch ich unnötige Using.
Und wie ich bereits gesagt habe, wird der Zweck dieser Klasse darin bestehen,
alle unsere API-Endpunkte zu enthalten.
Und das tun wir, indem wir verwenden, was wir als Erweiterungsmethoden kennen.
Erweiterungsmethoden gehören zu statischen Klassen, welche wir wirklich kennen.
Bevor wir hier unsere Erweiterungsmethode definieren, beginnen wir damit, durch
unsere Spielesammlung zu stöbern.
Also wählen wir hier die vollständige Sammlung aller
Spiele aus – die umfangreichste.
Rechtsklicken wir.
Wir schneiden das hier heraus und bringen es zu den Spiele-Endpunkten, CS.
Fügen wir es direkt genau hier in unsere neue Klasse ein.
Lass uns das hier so noch etwas besser formatieren.
Lass uns das Game-DTO behandeln.
Lass uns das so machen, damit wir unsere Spielstore-API importieren können.
DTO NextSpace.
Und da wir jetzt soweit sind
In eine passende statische Klasse.
Wir müssen das richtig definieren.
Also wird das hier eine private statische Liste von Spiel-DTOs,
die wir Spiele nennen.
Außerdem, da wir nach dem Erstellen unserer Games-Endpunkt-Klasse keinen neuen
Wert mehr in dieses Games-Objekt zuweisen werden, ist hier eine gute Konvention,
dieses Objekt als readonly zu definieren.
Also setzen wir readonly, wodurch die Definition unserer
Liste hiermit abgeschlossen ist.
Wenn wir nun wieder zu ES zurückkehren, ist als Nächstes auch die Definition
unserer GI-Endpunkt-Namenskonstante dran.
Lass uns das beseitigen und es oben in unseren Gains-Endpunkt
als eine Konstante aufnehmen.
Jetzt ist es Zeit, unsere Erweiterungsmethode zu festlegen.
Also scrollen wir nach unten.
Gleich nach der Liste definieren wir die Methode.
Es wird eine statische Methode sein; Erweiterungsmethoden bleiben statisch.
Wir geben doch void zurück.
Nennen wir dieses hier.
Spiele-Endpunkte abbilden.
Da diese eine Methode alle Endpunkte abbilden wird, müssen wir definieren,
was genau wir erweitern wollen.
Das bedeutet, dass wir dem Objekt, das hier übergeben wird, neue Methoden
hinzufügen, um ein Objekt zu erweitern.
Wir fangen damit an, zu definieren, indem wir dieses Schlüsselwort
verwenden, und legen dann fest, was erweitert werden soll.
Das, was wir hier erweitern wollen, führt zurück zu Program.cs.
Wir möchten hier das App-Objekt erweitern, das wirklich vom Typ Webanwendung ist.
Dafür gehen wir hier zurück und definieren die Webanwendung.
Rauf, dann legen wir den Körper der Methode fest, bitte.
Dafür.
Im Grunde müssen wir nur die Definition aller unserer Endpunkte einbringen.
Also lasse ich mir hier einfach alles bis zum Löschpunkt greifen und mit der rechten
Maustaste klicken und Ausschneiden.
Aber zurück zum Games-Endpunkt, fügen wir einfach ein, was wir gerade kopiert haben.
Und jetzt mal
Wir tun dasselbe wie früher, aber diesmal im Zusammenhang mit
dieser neuen Erweiterungsmethode.
Beachte, dass es im Wesentlichen derselbe Code ist.
Nichts ändert sich.
Wir fügen weiterhin alle Methoden zur Webanwendung hinzu.
Aber jetzt liegt diese Methode in dieser Map bei den Spiel-Endpunkten.
Und damit können wir wieder zum Programm Cs zurückkehren, und hier sehen wir
jetzt wirklich diesen leeren Raum; wir können nun eindeutig 'up dot map' sagen.
Spiele-Endpunkte, korrigiere Groß- und Kleinschreibung, und
so machen wir es, bitte, ja.
Lass Strg-Punkt verwenden.
Um unseren neuen Spiele-Shop zu importieren, die API,
diesen Endpunkt Aspace.
Räumen wir dort auch kurz diesen Bereich auf.
Und jetzt ist dies der vollständige Inhalt unseres Programms, dieser
CS-Kurs, wie man sieht, wird es wirklich ganz viel leichter zu warten sein.
Anstatt hier Unmengen Zeilen Code zu haben.
Nun gehen wir hier wieder zu den Spiel-Endpunkten zurück, und noch
etwas, das wir tun können, ist auch.
Vereinfache ein wenig die Art und Weise, wie wir unsere Endpunkte definieren,
denn wie du sehen kannst, definieren wir unsere Gains-Route mehrfach, richtig?
Wir definieren sie hier und dort im GET-Endpunkt, und wirklich
in jedem einzelnen Endpunkt, und das ist fehleranfällig.
Stattdessen können wir das tun, was man als sogenannte Route-Gruppe bezeichnet.
Das wird den Basisteil des Ausdrucks eindeutig definieren, und dann können wir
jeden einzelnen der Endpunkte in diese Gruppe sicher und zuverlässig einfügen.
Dazu öffnen wir hier eine neue Zeile, und wir sagen hier einfach wirklich,
sehr deutlich, bitte, noch, bar group equals up that map group here.
Wir führen nun das eigentliche Pad hier direkt ein, das Slash Games
sein wird, wie vorgesehen, aktuell.
Lass mich dieses hier kopieren.
Wir legen es hierher, ganz bequem.
So das hier ist unsere Gruppe.
Und jetzt, statt Map-get und Map-post auf dem ursprünglichen
App-Objekt aufzurufen, können wir sie nun am Gruppen-Objekt aufrufen.
Also lass mich die Gruppe kopieren und lass uns alle unsere App-Aufrufe
vollständig durch Gruppe ersetzen.
Also jetzt Gruppen-Map, get Gruppen-Map, post, bitte.
Gruppen-Map setzen und auch Gruppen-Map, sofort löschen, bitte.
Nun ist natürlich wirklich der nächste Punkt, dass wir nicht mehr
für jeden einzelnen Endpunkt Gains definieren müssen, weil sie in der
Praxis von der Gruppe vererbt werden.
Also können wir das jetzt auf einfach nur '/' reduzieren, was
immer noch zum Endpunkt führt.
Es muss unter Slash-Gains definiert werden, aber der Endpunkt selbst
muss das nicht definieren.
Das wird aus der Route-Gruppe entnommen, in der Regel.
Gleiches gilt, auch hier.
Wir können MapKit anhand der ID verwenden, falls nötig.
Dieses hier können wir eventuell entfernen.
Vielleicht ist es so: Map-Post kann so sein; Map-Put könnte so sein;
und Map-Delete könnte auch so sein.
Ein wichtiger Aspekt der REST-API-Entwicklung ist die Prüfung
der Eingaben an unseren Endpunkten.
Um zu sehen, warum das wichtig ist.
Mal sehen, was passiert, wenn wir hier unsere POST-Anfrage ändern, damit.
Wir geben keinen Namen für das Spiel an, oder?
Also lasse ich das hier komplett weg.
Jetzt hat das Spiel keinen Namen, und selbst damit klicke
ich auf Senden der Anfrage.
Mal sehen, was passiert.
Okay, so wurde die Ressource erstellt.
Wir haben hier eine 201 erstellt.
Allerdings haben wir jetzt wieder was ohne Namen.
Als Teil unserer API-Ressourcen.
Also sind das inkonsistente Daten.
Und das ist etwas, das vielleicht in Zukunft zu Problemen führt.
Schauen wir uns jetzt an, wie wir das verhindern können.
Lass uns das hier schließen, und ich werde jetzt mal meinen Server stoppen.
Gehen wir zu unseren Endpunkten und Gains-Endpunkten, und suchen
wir hier den POST-Endpunkt, um zu sehen, was wir dagegen tun können.
Eine Sache, die wir tun könnten, ist zum Beispiel, wenn wir dieses neue Spiel
mit einem Create-Game-DTO erhalten.
Nun können wir hier vorgehen und die Eigenschaften validieren,
bevor irgendeine der weiteren Logik fortgesetzt wird, richtig?
Also hier in meiner Zeile 49 könnten wir Folgendes tun: Wenn der String neu
oder leer ist, dann erzeugen wir einen neuen Game.Name; wir könnten außerdem
so etwas wie 'return results.Request' verwenden, und wir könnten hier sogar
eine Meldung bereitstellen, möglicherweise eine detaillierte Meldung, oder?
Also muss ein Name da sein, sonst klappt der Rest der Logik
nicht, wenn der Name fehlt.
Aber natürlich, selbst wenn wir das tun, müssen wir auch jedes
Merkmal unseres DTO prüfen, richtig?
Sie ermitteln den Preis.
Alle übrigen Eigenschaften dienen und zwar dazu, sicherzustellen, dass
wir wirklich auch alles validieren.
Das würde klappen, aber diese Methode wird sehr ausladend.
Und wenn wir das wirklich für jeden Endpunkt tun, führt das
zu vielen Validierungszeilen.
Stattdessen entferne ich diese Zeilen sofort, bitte.
Was wir tun können, ist, unser DTO so zu ändern, dass die Eigenschaften
Validierungsregeln haben.
Welche Validierungsregeln gelten für sie, bitte?
Hier drücke ich F12, um zur Definition unseres CreateGameDTO zu gelangen.
CreateGameDTO.
Und was wir tun können, ist zu definieren, was als Datenanmerkungen
bekannt ist, bei den Eigenschaften.
So zum Beispiel gilt für unseren Namen, dass der Name erforderlich ist.
Und dazu benutze ich Strg.
Punkt und wähle das System, das Component Model und den DataAnnotations-Namensraum.
Dieses Attribut sorgt dafür.
Schon bevor das DTO-Objekt in unseren Endpunkt aufgenommen wird, validiert
ASP.NET Core, dass der Name wirklich einen Wert hat, ansonsten liefert
es von selbst einen Fehler zurück.
Jetzt reicht es nicht aus, dieses Attribut hier in unsere DTO-Eigenschaft einzufügen,
damit die Eingabevalidierung erfolgt.
Sie müssen außerdem die Validierungsdienste aktivieren
oder registrieren, damit ASP.NET Core sie dafür verwenden kann.
Gehen wir zurück zu unserem Explorer Contra E. Gehen wir in das
Programm, das zur CS-Datei gehört.
Und hier können wir unser Builder-Objekt verwenden, um zusätzliche Dienste
zu registrieren, die wir als Teil unserer Anwendung aktivieren möchten.
Dafür füge ich hier einfach ein paar kurze Zeilen hinzu; Folgendes tun wir.
Wir sagen: Builder, diese Dienste – das ist die Sammlung
aller Dienste, die wir auch mit der Anwendung registrieren möchten.
Und wir fügen Validierung hinzu.
Damit werden die Validierungsdienste für jeden einzelnen Endpunkt
unserer API verfügbar sein.
Also, wenn wir die Anwendung noch einmal ausführen, machen wir
einfach den zehnten Durchlauf.
Okay?
Gehen wir also wieder zu Games bei H C#, TP, und versuchen
erneut diese POST-Anfrage, die keinen Namen hat, richtig?
Also senden wir die Anfrage, und dieses Mal.
Wie vermutet, erhalten wir nun sofort vollautomatisch dort
eine schlechte Anfrage, und hier unten sieht man eine sehr schöne
Fehlerauskunft, die deutlich sagt, dass ein oder mehrere
Validierungsfehler tatsächlich aufgetreten sind, und sie zeigt,
welches Feld den Fehler verursacht hat.
In diesem Fall handelt es sich um die Name-Eigenschaft, und hier steht,
dass das Namensfeld erforderlich ist.
Wie Sie sehen, ist es wirklich leicht umzusetzen, und es war überhaupt nicht
nötig, die Logik des Endpunkts zu ändern.
Es hat nur das Attribut angeschaut, das wir im Game-DTO hinzugefügt haben.
Jetzt stoppe ich meinen Server, und wir sollten das noch ein
wenig weiter verbessern, indem wir prüfen, dass nicht nur der Name
erforderlich ist, sondern auch.
Wir wollen nicht zulassen, dass Spielnamen zu extrem langen Zeichenketten werden.
Zum Beispiel können wir hier die Zeichenlänge festlegen und hier den
Wert der maximalen Länge für diese Zeichenkette sorgfältig angeben.
Nehmen wir also an, dass es nur fünfzig Zeichen sind.
So wäre der längstmögliche Name eines unserer Spiele, definitiv.
Also damit: Wenn wir die Softwareanwendung erneut ausführen, machen wir den Net Run.
Lass uns bei HGTP wieder zu den Spielwelten zurückkehren.
Aber diesmal entferne ich das wirklich einfach.
Das funktioniert gut.
Ich werde diesen Namen mehrmals hintereinander kopieren und einfügen.
Also sollten diese wirklich länger als 50 Zeichen sein.
Und heute werde ich zurückkehren.
Los geht's: Ich werde versuchen, eine Anfrage zu senden, und wie erwartet
erhalten wir erneut eine fehlerhafte Anfrage, doch diesmal nicht, weil
uns der Name fehlt, sondern wie Sie hier deutlich sehen können, muss der
Feldname eine Zeichenkette mit einer Höchstlänge von 50 Zeichen haben.
So lässt sich die Länge Ihrer Zeichenfolgen überprüfen.
Lass uns das hier schließen.
Entferne diese Zusatz-Strings.
Server stoppen.
Dann haben wir das für unsere Namenseigenschaft erledigt.
Vielleicht möchten wir dasselbe auch für unseren Spiel-Generator tun.
Richtig?
Dann kopiere ich das hierher.
Für unsere Generierung brauchen wir kürzere Zeichenketten.
Sagen wir also 20 Zeichen.
Und dann legen wir auch unseren Preis fest.
Was den Preis betrifft, ist es so, dass wir sicherstellen möchten,
dass unser Preis eine positive Zahl ist, und vielleicht möchten
wir auch wirklich keine Preise von mehr als Hundert Dollar zulassen.
Um das Ganze zu erläutern, können wir hierfür das Bereichs-Attribut verwenden.
Also werde ich nunmehr das Wort Range nennen und es dann benutzen.
Von eins bis hundert.
Also, jetzt, falls wir die Anwendung erneut ausführen, bringen wir dies
wieder zu Games zurück, H C#, TP.
Dieses Mal versuchen wir zudem, ein Spiel mit einem Preis
von fünfhundertneunundfünfzig Dollar einzuführen.
Also senden wir nun eine Anfrage, und wie man deutlich sehen kann,
erhalten wir erneut eine fehlerhafte Anfrage, und diesmal steht hier
klar, dass das Feld Preis zwischen eins und hundert liegen muss.
Ein solcher Preis ist nicht gestattet.
Ich.
Okay, lass uns das hier schließen.
Wir stoppen den Server, und an diesem Punkt erledigt das unser
Create-Game-DTO; dasselbe sollten wir auch für das Update-Game-DTO tun, oder?
Wir möchten außerdem Validierungen für PUT-Anfragen einführen.
Für diesen Fall werde ich jetzt einfach diese Eigenschaften kopieren, um es
etwas schneller zu machen, damit wir später rascher weiterarbeiten können.
Also kopieren.
Lass uns C# Shift E ausführen, das Game-DTO aktualisieren, und
lass uns das, was ich gerade kopiert habe, hier einfügen.
Hier ist dieselbe Reihe von Eigenschaften.
Am Ende lass uns C#-Kontrollen hier verwenden, um System-C# vorzustellen und
Modelldatennotationen zu vergleichen.
Und jetzt sollten wir denselben Validierungsumfang haben.
Bei unserem PUT-Endpunkt.
Also probieren wir das jetzt sehr schnell aus.
Dann, dann lauf.
Lass uns in unsere Spiele bei HTP gehen.
Lass uns dieses Mal in unsere PUT-Anfrage gehen.
Das wird Spiel Nummer eins sein, und dieses Mal versuchen wir es einfach.
Was passiert, wenn wir ein leeres General-Feld haben, richtig?
Also, ein leeres General-Feld: Wir klicken auf Senden der Anfrage.
Und sicher genug, wieder einmal haben wir eine schlechte Anfrage erhalten,
und diesmal liegt es daran, dass das General-Feld erforderlich ist.
Sie können auch andere Eigenschaften prüfen.
Für unsere PUT-Anfrage denke ich wirklich, du siehst, wie wirklich einfach es ist,
Eingabevalidierung durch Datenanmerkungen und die Validierungsdienste von
ASP.NET Core zu ermöglichen.
Jetzt möchten wir der REST-API eine Datenbankanbindung geben, damit alle Daten
nach der Replikation gespeichert bleiben.
Wenn eine Anfrage zum Anlegen eines Spiels in unserer API eingeht, möchten
wir das Spiel in der Datenbank speichern.
Und wenn der Client eine Auflistung von Spielen anfordert, möchten wir diese
Auflistung aus der Datenbank abfragen.
Aber es gibt ein Problem.
Die Datenbank spricht nicht die gleiche Sprache wie deine C# .NET Core API.
Ihre API ist in C# (C-Sharp) geschrieben, aber Ihr relationaler
Datenbankserver versteht nur SQL bzw.
die SQL-Sprache.
Das bedeutet, um die Anfrage zum Abrufen von Spielen zu erfüllen, muss Ihr
C#-Code zusammen mit dem API-Code die API-Anfrage in eine sorgfältig erstellte
SQL-Abfrage übersetzen und diese Abfrage dann an den Datenbankserver senden.
Der Datenbankserver führt die Abfrage aus; Ihr C#-C#-R-Code muss
alle ergebenden Rollen zurücklesen und sie in API-Antwort übersetzen.
Das verursacht noch einige Probleme.
Als C#-Entwickler müssen Sie jetzt eine neue SQL-Sprache lernen, um
die nötigen Abfragen zu erstellen, und sie gut beherrschen, damit Sie
wirklich gute Leistung erzielen.
Sie müssen viel zusätzlichen Datenzugriffscode schreiben, dessen
einziger Zweck darin besteht, Dinge von C# nach SQL und umgekehrt zu übersetzen,
und mit unerwarteten Fehlern umgehen.
Beim Sprechen über Fehler ist dieser Ansatz fehleranfällig;
es ist leicht, Fehler zu machen, wenn Dinge seitenweise übertragen.
Und Sie müssen Ihre Anfallmodelle manuell mit den passenden Tabellen der Datenbank
abgleichen; das ist nicht einfach.
Hier können optimierte relationale Mapping-Techniken oder ORM viel bewirken.
Aber was ist OM?
Nun, zurück zu unserem Spotify-Beispiel: Stellen Sie sich vor, Ihre Anwendung
wurde nach einem objektorientierten Paradigma erstellt und enthält
daher Objekte zur Darstellung von Songs, Künstlern und Playlists.
Und wenn Sie mit einem relationalen Datenbankserver arbeiten, besteht
eine gute Chance, dass Ihre Datenbank entsprechende Tabellen
für jedes dieser Objekte hat.
Jetzt muss kein eigener Code mehr geschrieben werden, um
Objekte auf Tabellen abzubilden.
Wenn Daten an die Datenbank gesendet oder von ihr empfangen werden müssen, richte
eine Zuordnung zwischen ihnen ein, damit dein Programm weiter mit Objekten arbeiten
kann, während ein ORM die Umwandlung von Objekten in Tabellen und zurück übernimmt.
Im Wesentlichen ist Objekt-Relationales Mapping eine Technik, Daten zwischen
einer relationalen Datenbank und einem objektorientierten Programm zu übertragen.
Und wie Sie sich vorstellen können, bringt es vielen Entwicklern Vorteile.
Und glücklicherweise enthält ASP.NET Core ein großartiges ORM-Framework
namens Entity Framework Core.
Also, was ist Entity Framework Core?
Es ist ein leichtgewichtiges, erweiterbares Open-Source-
und plattformübergreifendes Objekt-Relationaler Mapper (ORM).
Entity Framework Core wird zwischen Ihrer REST-API und Ihrem Datenbankserver sitzen.
Neben der Abbildung Ihrer .NET-Objekte auf Datenbanktabellen übersetzt es Ihren
Datenzugriffs-Code in SQL-Anweisungen, die der Datenbankserver verstehen kann,
und es übersetzt außerdem alle aus der Datenbank resultierenden Daten in Objekte,
die Ihre API mühelos verwalten kann.
Die Nutzung des Anti-Framework-Kerns in Ihren Dan-Anwendungen bringt Vorteile.
Sie müssen doch keine neue Sprache lernen.
Sie können alle Datenzugriffsaufgaben mit Ihrer vertrauten C#-Sprache durchführen.
Der für den Datenzugriff notwendige Code ist minimal.
Weil jedes DD-Framework den Großteil davon übernimmt.
In der Tat können Sie LINQ verwenden, um die meisten Abfragen
Ihrer Datenbank auszuführen.
Es gibt Werkzeuge, die deine C#-Modelle mit der DB synchron halten, damit
du das nicht mehr manuell tun musst.
Das Framework kann Änderungen verfolgen.
Zur Laufzeit stehen deine C#-Objekte, damit klar ist, welche Änderungen
an DB gesendet werden müssen, wenn Zeit ist, die Daten zu speichern.
Schauen wir uns nun an, wie man mit antide Framework Core der API unseres Spielstores
eine Datenbankunterstützung hinzufügt.
Der erste Schritt bei der Integration unserer S Vnet Core-API in eine
relationale Datenbank besteht darin, unser Datenmodell genau zu definieren.
Das Datenmodell wird sämtliche Klassen vollständig umfassen.
die wir nutzen werden, um Objekte zu machen, die gespeichert werden müssen.
In unseren Datenbanktabellen.
Also fangen wir damit an, unseren Lösungsexplorer zu öffnen.
Vielleicht klicken wir dann rechts auf den neuen Ordner der Game Store API.
Und lassen wir es Modelle nennen.
Klicken wir jetzt im Modellordner mit der rechten Maustaste.
Eine neue Datei.
Das wird wirklich eine Klasse sein, und nennen wir diese hier 'game'.
Großartig.
Öffne unser Spiel.
Mach C#-Datei.
Lösche unnötiges Using.
Und jetzt stellen wir mal alle Eigenschaften vor.
Unser Gangmodell.
Der erste wird unsere ID sein, also definieren wir bitte mal eine
öffentliche ID mit einer Sammelantwort.
Dann definieren wir jetzt bitte unseren öffentlichen String-Namen mal.
Was übrigens dazu führt, diese Warnung hier anzuzeigen, weil der Compiler darauf
besteht, dass wir sicherstellen, dass die Namenseigenschaft nach dem Erzeugen
einer Instanz der Game-Klasse I zu jedem Zeitpunkt immer einen Wert besitzt.
Eine Möglichkeit, dies zu lösen, besteht auch darin, die
Namenseigenschaft möglicherweise mit leerem String zu initialisieren.
Eine andere Lösung besteht darin, die Namenseigenschaft kennbar zu machen.
Wenn du das tust, ist es ein kenntbares Objekt, beim Erzeugen des Objekts
muss kein Wert festgelegt werden, wir möchten jedoch einen Wert haben.
In der Namenseigenschaft eines Spiels ergibt es keinen Sinn,
ein Spiel ohne Namen zu haben.
Was wir tun können, ist tatsächlich das in diesem ganz besonderen Zusammenhang
erforderliche Schlüsselwort in der Praxis zu verwenden, damit der
Compiler von uns verlangt, dass wir einen Wert für den Namen angeben.
Nun, als Nächstes müssen wir unser Spielkonzept festlegen.
Doch zu diesem Zeitpunkt werden wir uns nicht mehr darauf beziehen.
Als einfachen String degenerieren.
Wir möchten in einer Datenbank eine eigene Tabelle für Generierungen haben,
und deshalb müssen wir Degenerieren als eine weitere Klasse definieren, die
Teil unseres Datenmodells sein muss.
Also gehen wir wieder in den Solution Explorer.
Klicken wir erneut auf Modelle, neue Datei, Klasse.
Äh, tippe hier Januar ein, bitte.
Öffnen wir jetzt Januar, bitte, zusammen.
Räumen wir das hier im Raum auf.
Und unsere Implementierung wird eine sehr einfache Klasse sein, die zudem
über eine öffentliche ID vom Typ Integer verfügen wird und zusätzlich
über einen öffentlichen, erforderlichen String-Name verfügt, und zwar eben
jeweils mit einem Getter und einem Setter.
Jetzt können wir wieder ins Spiel gehen.
Und wir können hier noch etwas hinzufügen.
Unser öffentliches Repository; daraus folgt tatsächlich, dass dies eine
zusammengesetzte Eigenschaft sein wird.
des Spielmodells.
Jetzt erneut erhalten wir wirklich die Warnung des Compilers, der verlangt,
dass wir hier einen Wert für unsere January-Eigenschaft setzen, weil der Typ
im Moment wirklich nicht machbar ist.
Und in diesem Fall werden wir diesen Typ wirklich durch das Hinzufügen des
Fragezeichens machbar machen, denn wie du im Verlauf des Kurses sehen wirst.
Es wird Situationen geben, in denen wir für diese zusammengesetzte allgemeine
Eigenschaft keinen Wert festlegen möchten.
Dies wird der Fall sein, wenn wir uns nur mit der Idee des Generators
befassen müssen, aber nicht mit dem Generator-Objekt, wenn wir nach
unseren Spielen suchen möchten.
Reicht es, Navigations-Eigenschaft in unserem Spielmodell zu haben,
die in die Generierung geht.
Es wird ausreichend sein, damit das Entity Framework verstehen kann,
dass es ein Fremdschlüssel sein muss.
Von unserer Spieltabelle in die Allgemeintabelle.
Allerdings ist es aus guter Praxis deutlich besser,
... Hier definieren wir deutlich ein weiteres Attribut, das
diesen Fremdschlüssel darstellt.
Also hier werden wir nun unser öffentliches Attribut definieren.
Damit weiß der Kern jedes D-Frameworks mit Sicherheit Bescheid.
Wir möchten jedoch diesen Fremdschlüssel von Game zu Generate haben, aber er
gibt uns die Möglichkeit, in vielen Szenarien direkt mit der Generate-ID
arbeiten zu können, ohne die gesamte Generate-Eigenschaft laden zu müssen.
Wenn wir Spiele aus der Datenbank abrufen möchten, was wesentlich
schneller sein wird, werden wir sehen, wie wir diese beiden Eigenschaften im
Verlauf der Implementierung unserer Endpunkte austauschbar verwenden,
und zwar Schritt für Schritt.
Auch, weil die generierte ID nicht bekannt ist, oder?
Also ist das nicht bekannt.
Es bedeutet, dass die Beziehung hier
Es wird ausdrücklich verlangen, dass einem Spiel-Datensatz eine
generierte ID zugeordnet wird; diese Zuordnung ist damit nicht optional.
Sie ist erforderlich, wie es sein sollte.
Nun vervollständigen wir unser Spielmodell, indem wir unseren
öffentlichen Dezimalpreis einführen und unser öffentliches
Veröffentlichungsdatum (nur Datum).
Und damit ist unser Datenmodell vollständig.
Bereit, Anti-Different-Work-Core in unsere API einzuführen.
Um Antide-Framework-Kern in unsere Vnet-Core-API zu integrieren, nutzen
wir ein neues Bibliothekenset, das standardmäßig nicht mit
Vnet-Core geliefert wird.
Diese Art Bibliotheken sind verteilt.
Pakete, die als NuGet-Pakete bekannt sind.
Und der Ort, an dem man sie findet, ist diese Seite no.org.
Dies ist das größte Repository für No-Pakete, und du solltest doch in
der Lage sein, jedes Nugget-Paket zu finden, das du jemals brauchst,
indem du es hier einfach suchst.
NDE Framework Core unterstützt mehrere DB-Anbieter.
Aber im Rahmen dieses Kurses verwenden wir SQLite, weil es sehr leichtgewichtig
ist und sich gut damit arbeiten lässt.
Wenn du dabei bist zu lernen, wie man mit Fin Core arbeitet, um den
ESQ Light-Datenbankanbieter für .NET Framework Core vorzustellen, ist das
Paket, das du verwenden möchtest, dieses hier, namens Microsoft.Data.Sqlite.
Hier können Sie auf Suche klicken, und es werden alle Pakete gefunden,
die dem Suchbegriff entsprechen.
In der Regel ist das allererste das, was Sie verwenden möchten.
Microsoft Entity Framework Code Dot Escalate.
Klicken Sie bitte darauf.
Auf dieser Seite finden Sie viele Details zu diesem Paket,
einschließlich der neuesten Versionen.
Auch der genaue .NET C#-String zum Paket installieren.
Wenn Sie .NET C#-CLI nutzen möchten,
Nun ist dies eine von mehreren Möglichkeiten, es zu tun, doch nochmals:
Da wir das C#-R-Entwicklerkit verwenden, gibt es einen einfacheren Weg, es
direkt aus VS Code heraus zu erledigen.
Also kehren wir zu VS Code zurück und öffnen den Solution Explorer.
Wir klicken mit der rechten Maustaste auf unser King Store a P-Projekt.
Wir wählen NuGet-Paket hinzufügen und suchen nach Microsoft Antide
Defined Work Code Esq Light Heat.
Gib ein
Unser Paket ist hier der allererste Eintrag.
Darauf klicken.
Und hier werden Sie aufgefordert, die Version zu wählen, die Sie für
Ihre Anwendung verwenden möchten.
Da unsere Anwendung auf .NET 10 abzielt, wählen wir die neueste stabile Version.
Für .NET 10, das hier gemeint ist, Version 10.0.0.1.
Also klicken wir auf diese hier, und dieses Paket ist installiert worden.
Nun gibt es keinen klaren visuellen Hinweis darauf, dass
das Paket installiert werden kann.
Aber öffnen wir hier unsere Abhängigkeiten und dort unseren Paket-Knoten, sehen
Sie, dass der .NET Framework-Code hier erscheint, was bedeutet, dass
das Paket installiert werden kann.
Und außerdem, wenn Sie auf das Projekt selbst klicken, sehen Sie auf der
rechten Seite, dass wir wieder zu unserem C#-Profil zurückkehren, und äh.
Wir finden diesen Knoten, einen Paketverweis, der die Installation
des Microsoft Entity Framework Core-SQL-Paket darstellt.
Ein Core-SQL-Paket mit der Version zehn Punkt null Punkt eins.
Super.
Wir haben jetzt Unterstützung von Entity Framework Core in unserer API.
Wollen wir mit dem Erstellen beginnen?
Die Objekte, die nötig sind, um unser Modell in SQLite-Tabellen abzubilden.
Also schließen wir das hier.
Gehen wir mal zurück in den Lösungs-Explorer.
Klicke mit der rechten Maustaste auf die Game Store-API.
Ordner neu erstellen.
die wir Data bezeichnen
Und Inside Data.
Rechtsklick und erstelle eine neue Datei, die eine Klasse ist.
Und wir wollen es in diesem Game Store-Kontext benennen.
Drücke Enter und öffne es bitte gleich in unserem leistungsfähigen Editor hier.
Using-Direktiven entfernen.
Und der Zweck dieser GameStore-Kontextklasse besteht darin,
wirklich dein DV-Kontext zu sein.
Welches im Kontext des Anti-Framework-Kerns eine Sitzung zwischen
Ihrer API und der Datenbank repräsentiert.
Und kann sowohl zum Abfragen verwendet werden.
Und speichert Instanzen der Entitäten in der Datenbank.
Man kann den DB-Kontext durchaus als Verbindung von Unit-of-Work-Mustern
und Repository-Mustern sehen.
Nun, um diese Game-Store-Kontextklasse in einen DB-Kontext zu verwandeln,
müssen wir sie aus der DB-Kontextklasse ableiten, die mit dem .NET
Framework Core geliefert wird.
Verwende ich C# Strg+Punkt, damit wir den Microsoft .NET Framework
Core-Namensraum einführen können.
Du musst deinem DB-Kontext auch sagen, wie er sich mit deiner Datenbank verbinden
soll, und das tust du, indem du die sogenannten DB-Kontext-Optionen übergibst.
Und das tust du, indem du die DB-Kontext-Optionen
übergibst, die man so nennt.
Hier werden wir einen Primärkonstruktor einführen, der DB-Kontext-Optionen
des Typs Game Store Context erhält.
Und nennen wir den Parameter einfach Optionen.
Jetzt senden wir dies in die nächste Zeile, und wir übergeben das
Options-Objekt an den Basiskonstruktor.
Mehrere Parameter, darunter Verbindungsstrings, werden im Rahmen
dieser Optionen empfangen, damit der King Store-Kontext weiß, wie
er mit Ihrer Datenbank spricht.
Wir sehen später, wie man eine Verbindungszeichenfolge
in die App einführt.
Doch so deklarieren Sie Ihren Kontext.
Und als Nächstes muss man Merkmale festlegen, die die Zuordnung
zwischen deinen Objekten und Tabellen der Datenbank darstellen.
Also, dafür führst du Folgendes aus: Wir definieren die folgenden Eigenschaften,
die wir festlegen werden, damit der Code die vorgesehenen Parameter besitzt.
Öffentliche DB: Spielesammlung.
Dafür nutzen wir control.here, Cantor, diese API und Modelle,
und nennen wir dieses Objekt hier 'games', damit der Zweck klar ist.
Jetzt hat das weder Gather noch Set, sondern ist einfach eine Eigenschaft,
die direkt auf ein Spiel-Set verweist.
Also handelt es sich wirklich um ein Objekt, das sowohl zum Abfragen als
auch zum Speichern von Spielinstanzen in diesem Fall verwendet werden kann,
und alle Linkabfragen, die Sie an dieses Spieleobjekt senden, werden in
Abfragen gegen die Datenbank übersetzt.
Und genauso wie wir die Menge der Spiele definieren, möchten wir auch
eine Menge für unsere Gens definieren.
Also definieren wir unsere öffentliche Gen-Menge.
Bezugnehmend auf Re, wird es künftig auf eine Menge von Genen wohl aufzeigen.
Dann ist das alles, was wir tun müssen, um DB-Kontext zu definieren.
Aber noch eine weitere Sache: Wir müssen uns tatsächlich registrieren.
Dieser Datenbankkontext, damit er in unserer gesamten
Anwendung verwendet werden kann.
Und dazu gehen wir in unseren Datei-Explorer.
Lass uns in unsere C#-Datei gehen.
Und wie wir Validierungsdienste hinzugefügt haben, können
wir auch unseren DB-Kontext nutzen, indem wir ihn einsetzen.
Muster heißt Abhängigkeitsinjektion.
Später lernen wir in diesem Kurs mehr über DI; aber ich zeige dir heute nur etwas.
Wie man die Verbindungszeichenfolge definiert, um sich mit der Esq
Lite-Datenbank zu verbinden, und wie man den DB-Kontext mit
dieser Zeichenfolge registriert.
Zunächst wird diese Verbindungszeichenfolge definiert.
Hier definieren wir einfach eine Variable und stellen sicher, dass dies vor der
Erstellung Ihres App-Objekts geschieht.
Es muss vorher erfolgen, damit es ordnungsgemäß registriert wird.
Bar-Beschränkung
Und hier verwenden Sie die korrekte Syntax für eine Verbindungszeichenfolge.
Das zielt auf eine SQI-Datenbank ab.
Daher soll hier die Datenquelle dem Gleichheitszeichen zugeordnet
werden, und auf der rechten Seite dieses Gleichheitszeichens geben
wir den Namen der physischen Datei an, die die Datenbank repräsentiert.
In diesem Fall nennen wir sie einfach game store dot db.
Es muss nicht dieser Name sein; wirklich jeder Name wäre möglich.
Es sollte etwas sein, das den Zweck der Datenbank wiedergibt, und da wir nun die
Verbindung festgelegt haben, können wir fortfahren und unseren neuen DB-Kontext
mit dieser Verbindung registrieren.
Dafür verwenden wir Builder, der auch Dienste anbietet,
die hinzufügen und eskalieren.
Und hier als Typparameter möchten wir ausdrücklich unseren Game-Store-Kontext
festlegen, der übrigens durch ctrl.here verwendet wird, um den
Game-Store, diese API sowie diese Daten ganz gezielt zu nutzen.
Und dann geben wir hier den eigentlichen Verbindungsstring an.
C#-String.
Damit ist unsere Anwendung bereit, mit der SQL-Datenbank zu sprechen.
Wir haben doch noch nicht die Datenbankdatei erstellt, damit die
Anwendung mit ihr sprechen kann.
Und dazu können wir auch die Migrationsfunktion des Entity
Framework Core verwenden.
Eine Datenbankmigration ist der Prozess, bei dem schrittweise das Schema der
Datenbank aktualisiert wird, um es mit dem Datenmodell der Anwendung in
Einklang zu bringen und dabei vorhandene Daten in der Datenbank zu erhalten.
In diesem Fall haben wir keine Datenbank, daher müssen wir eine Migration
durchführen, um das anfängliche Schema der Datenbank zu erstellen.
Dazu brauchen wir zwei Dinge.
Zuerst benötigen wir das .NET EF-Werkzeug, das die Befehle bereitstellt, die
erforderlich sind, damit die Migration eingeleitet und gestartet werden kann.
Dafür gehen wir hier zu unserer NuGet.org-Seite, und im Suchfeld können
wir ganz einfach nach .NET suchen.
EF, dann klicken wir bitte auf Suchen.
Das sollte zweifellos das allererste Ergebnis darstellen.
Hier drüben sehen Sie den NET EF.
Und hier möchten wir die neueste stabile Version des Pakets auswählen, die hier
als Version 10.0 0.1 angegeben ist.
Zum Zeitpunkt meiner Aufnahme kopieren wir diese Befehlszeile oben.
Also kopieren wir sie zurück in VS Code.
Öffnen wir nun unser Terminal Contra J.
Lasst uns das Kopierte mit Leerzeichen versehen.
Beachtet, dass dies ein globales Werkzeug sein wird.
Also ist dies ein globales Werkzeug.
Es hat nichts mit dem aktuellen Standort Ihres Projekts zu tun.
Sobald Sie es installieren, wird es für jedes Projekt auf
Ihrem Computer verfügbar sein.
Und drücken Sie Enter.
und Tool installiert.
Als Nächstes benötigen wir bitte ein neues NuGet-Paket.
Also schließen wir das hier jetzt.
Gehen wir jetzt zurück in unseren Lösungs-Explorer.
In diesem Fall klicken wir bitte mit der rechten Maustaste auf
das NuGet-Paket 'Game Store API'.
Und das Paket, nach dem wir suchen, ist genau dieses hier, genannt Microsoft
dot Antide Framework, Core.Design.
Drücken wir Enter.
Es wird das Erste in der Liste sein.
Geben wir den Framework-Code ein, das Design.
Wählen wir die neueste stabile Version aus, 10.0 0.1, und das Paket ist
installiert; wir können bestätigen, dass das Paket vorhanden ist, indem wir zu
den Abhängigkeiten der Pakete gehen.
Unser Paket befindet sich hier, und wir könnten es auch bestätigen,
indem wir in die Projektdatei gehen.
Wir sollten hier das installierte Paket sehen können.
Nun, der Grund, warum wir dieses No-Package brauchen,
ist, dass es im Wesentlichen das Gehirn der EF Core-Tools ist.
Es liefert das .NET-EF-Tool.
Die zusätzlichen Dienste, um Kontext zu entdecken und Modell zu erstellen.
Dadurch erzeugt Migrationen, Scaffold und Code.
und paar Dinge.
Also, da wir jetzt das .NET Entity Framework installiert haben und
das NuGet-Paket vorhanden ist, können wir sofort fortfahren und
unsere erste Migration erstellen.
Dafür öffnen wir unser Terminal.
Dann bereinigen wir hier alles und wechseln in unser
Game Store API-Verzeichnis.
Also: Game Store API.
Um das Tool auszuführen, fügen wir hier mit .NET EF-Migrationen
eine neue Migration hinzu.
Dafür müssen wir einen Namen für diese Migration angeben, der in diesem Fall
die anfängliche Erstellung sein wird.
Also nennen wir sie einfach Anfangserstellung.
Und außerdem finde ich es praktisch, eine Zuordnung der
erzeugten Dateien bereitzustellen.
Das klappt damit, Dash-Ausgabe, mein Lieber.
Dann wollen wir Zuordnung auswählen.
Lassen Sie uns kurz unseren Datei-Explorer Contra E ansehen, um zu verstehen, wo
wir diese Migration erzeugen sollten.
Lassen wir das kurz zuklappen.
Wir möchten unter unserem Datenverzeichnis gehen, direkt darin.
Dort befinden sich unsere EF-verknüpften Dateien.
Also, was Apple Deer betrifft, lassen wir hier jetzt Daten eingeben,
und danach legen wir ebenfalls ein Migrationsverzeichnis an.
Okay, also, das ist unser wirklich vollständiger Befehl.
Drücken wir Enter.
Und jetzt wird das Tool unsere Anwendung vollständig erstellen und anschließend
alle Datenbank-Migrationsdateien vollständig erzeugen, eben.
Nun, gehen wir wieder in den Datei-Explorer; dort sollte stehen, dass
ein neuer Migrationsordner erstellt wurde.
Öffnen wir ihn, finden wir einige Dateien.
Die soeben erzeugte Migration repräsentiert.
Nun, unter diesen Dateien schauen wir uns tatsächlich die allererste Datei an.
Diese hier endet mit "initial create".
Übrigens wird hier eine Nummer stehen, die dem Datum und der Uhrzeit entspricht,
zu der du diese Migration erzeugt hast.
Aber jetzt, wenn wir "initial" öffnen, diese Cs hier erzeugen, lass uns
das hier und jenes zusammenklappen.
Wir sehen, dass es so wird.
Nur eine weitere Klasse, die in diesem Fall aus Migrationen stammt, von EF
Core kommt und einige Methoden hat.
Die erste Methode hier ist die Op-Methode.
Es gibt jene, die die Logik enthält, Ihre Datenbank vom aktuellen Zustand
in den neuen Zustand zu überführen.
Und hier sehen Sie, wie die Create-Table-Methode aufgerufen wird,
um die Erstellung dieser neuen Tabelle in der Datenbank zu definieren.
Diese Tabelle wird unsere großzügige Tabelle sein.
Wir legen Spalten fest, die in die Tabelle aufgenommen werden müssen, und
legen fest, dass der Primärschlüssel der großzügigen Tabelle sein soll.
Nachdem diese Tabelle festgelegt ist, erstellen wir die zweite und wichtigste
Tabelle: unsere Spiele-Tabelle.
Hier sehen wir die Spieltabelle; hier sind alle Spalten, die zu
dieser Tabelle gehören und sich heute ganz eindeutig zuordnen lassen.
Das Spielmodell in unserem C#-Code.
Mir fällt auf, dass dieses hier tatsächlich alle richtigen Datentypen
für die Datenbank definiert.
Datenbank deeskalieren.
Wenn wir weiter nach unten gehen, finden wir auch die Einschränkungen dieser
Tabelle, nämlich den Primärschlüssel der Games-Tabelle und außerdem den
Fremdschlüssel, der unsere erzeugte ID in der Games-Tabelle mit der
ID der Genre-Tabelle verbindet.
Wenn wir weiter nach unten gehen, finden wir außerdem den normalen Index,
der auf dieser Tabelle definiert ist.
Die Spalte, die als Fremdschlüssel ausgewählt wurde — in diesem
Fall die generierte ID.
Wie bei der Op-Methode haben wir auch die Down-Methode, die dazu
dient, das Schema wieder in den vorherigen Zustand zu versetzen.
Falls du jemals mal einen Migrationsschritt entfernen musst,
Dies ist die Logik, die zuerst die Games-Tabelle löscht und danach
die großzügige Tabelle löscht.
Sie folgt der richtigen Reihenfolge, damit die Schritte gelingen.
Nun, da wir unsere Migrationsdateien erzeugt haben, ist es an der
Zeit, die Action-Migration auszuführen, und das können wir
erneut über das .NET EF-Tool tun.
Also schließe ich einfach alle diese Dateien.
Lass uns zurück in unser Terminal gehen.
Ich werde das hier tun und den folgenden Befehl ausführen: net EF database update.
Drücke Enter, und das ist der Befehl, der all den Migrationscode nimmt und ihn auf
unserem Rechner ausführt, um eine erste Version unserer Datenbank zu erstellen.
Lass mich Terminalausgabe erweitern.
Wir sehen hier viele Zeilen.
Wie Sie sehen, besteht hier eine Menge SQL-Befehle, die ausgeführt wurden,
um unsere SQL-Datenbank zu erstellen.
Und dazu gehe ich nicht weiter ins Detail.
Jeder Befehl im Detail, aber hier sind folgende Punkte zu beachten.
Zum Beispiel haben wir hier unsere EF-Migrations-Historietabelle direkt
hier, die dazu dient, die zuletzt auf Ihre Datenbank angewendete Migration
genau zu verfolgen, damit bei der nächsten Migration bekannt ist, von welcher
Migration aus gestartet werden muss.
Wir gehen weiter runter und sehen, dass die Migration hier angewendet wird.
So wird genau die Migration verwendet, die wir eben erstellt haben, und das bedeutet,
dass sie ein paar Dinge tun muss, oder?
So muss sie unsere Migrations-Tabelle erstellen.
Hier ist die Migrations-Tabelle.
Dann muss sie die Games-Tabelle hier erstellen, und danach
führt sie weitere Befehle aus.
Außerdem wende den Index an, richtig?
Der Index für den Fremdschlüssel fügt unsere neue Migration in die
EF-Migrationsverlaufstabelle ein, und danach wird die Migration abgeschlossen.
Und weil all das jetzt erledigt ist, sollten wir sehen können, ob wir im
Datei-Explorer zurückgehen können.
Vielleicht klappen wir das Terminal zusammen.
Zunächst sollten wir erkennen, dass hier unsere brandneue DV-Datei
vom Spiele-Shop generiert wurde.
Also ist unsere Datenbank jetzt aktiv.
Und an diesem Punkt ist es nicht verkehrt, diese Datenbank zu
durchsuchen, um zu prüfen, ob das richtige Schema erzeugt wurde.
Und der Weg dazu besteht darin, eine neue VS Code-Erweiterung zu installieren.
Dann lasse ich für einen Moment meine Aktivleiste öffnen.
Fokusleiste.
Lass uns hier in den Erweiterungsbereich gehen, und diesmal suchen wir
nach der SQ light-Erweiterung.
Es wird diese hier sein, SQ light.
Hier ist dieses Auto.
Wie dort zu sehen ist, ist Alex C# v C# C#, eine sehr beliebte Erweiterung.
Es ist sehr einfach, aber sehr praktisch, um Ihr S-Schema zu erkunden.
Klicken wir also auf Installieren.
Okay, installiert.
Also schließen wir das.
Gehen wir in unseren Datei-Explorer zurück.
Jetzt haben wir die Erweiterung; was tun wir?
Führe einen Rechtsklick auf die Game Store DB aus, und dort werden wir einen
brandneuen Befehl finden, der 'Open database' heißt und oben angezeigt wird.
Wenn wir darauf klicken, öffnet sich auf der linken Seite ein völlig neuer Bereich,
der den Namen 'SQ Light Explorer' trägt.
Okay, jetzt, bevor wir dahin gehen, lasse ich kurz meine Aktivleiste aus,
damit wir besser sehen können – und vielleicht auch meine Menüleiste.
Danach öffnen wir den Explorer.
Was wir sehen werden, ist, dass unsere Datenbank hier liegt, und wir können
beginnen, Dinge zu erweitern, um das Schema der Datenbank zu erkunden.
Also wie gesagt: Hier ist unsere EF-Migrationsverlaufstabelle,
genau, richtig?
Sie enthält wirklich die Migration, die wir gerade ausgeführt haben.
Um zu sehen, was drin steht, klicken wir hier auf den Play-Button, bitte.
Und ja, der Inhalt ist so beschrieben.
Hier ist die Idee unserer Migration, und wir haben die EF Core-Version,
die diese Migration erzeugt.
Wie gesagt, so verfolgt EF Core die zuletzt verwendete Migration, damit
die nächste Migration weiß, wie sie auszuführen ist, sobald sie kommt.
Hier haben wir unsere Tabelle.
Wir sehen Spalten, ID und Name, Datentypen.
Und klar haben wir unsere Spieltabelle mit allen entsprechenden Spalten, wie üblich.
Nun, eine Sache, die ich für die lokale Entwicklung wirklich
nützlich finde, ist, beim Start der App etwas Code hinzuzufügen,
damit die neuesten Migrationen immer beim Start angewendet werden.
So müssen wir das .NET nicht ständig laufen lassen.
EF-Datenbank-Update-Befehl jedes Mal, wenn wir eine Migration vornehmen.
Dann zeige ich dir jetzt, wie das geht.
Gehen wir doch wieder in unseren Explorer.
Oder eigentlich ist es unser Solution Explorer, weil wir eine ganz neue
Klasse erstellen müssen, die wir hier in unser Datenverzeichnis einfügen werden.
Machen wir Rechtsklick auf Neue Datei.
Es wird eine Klasse sein.
Benennen wir sie hier: Data Extensions.
Öffnen wir Extensions.cs.
Bereinigen wir die Using-Anweisungen, und dies wird eine statische Klasse sein,
weil sie eine Erweiterungsmethode haben wird, die wir aufrufen werden – public
void oder public static void migrate.
Diese Vorgehensweise wird unsere Webanwendungsklasse
App umfassend erweitern.
und der Code, den wir hier haben, wird recht einfach sein
Zuerst.
Wir erstellen etwas, das man Umfang bezeichnet.
Was nötig ist, damit wir Zugriff auf eine Instanz unseres
GameStore-Kontexts erhalten.
Das hängt mit der Dependency-Injection von ASP.NET Core zusammen, das wir
im Kurs später behandeln werden.
Also, mach dir bitte keine Sorgen.
Ich werde das später noch detaillierter erläutern.
Allerdings beginnen wir vorläufig damit, die folgenden Zeilen jetzt einzugeben.
Wir verwenden daher VAR-Scope gleich App, das Dienste bietet, die erzeugen.
Der Umfang.
Und danach besteht die Möglichkeit, eine vollständige Instanz des DbContext
abzurufen, indem wir den folgenden Ausdruck verwenden: var dbContext
= scope.ServiceProvider.GetRequiredService<GameStoreContext>();
Vielleicht schick ich's zur nächsten Folie, damit wir's besser sehen.
Und jetzt, da wir Zugriff auf eine Instanz des DV-Kontexts
haben, können wir jene Datenbank migrieren, ohne weitere Verzögerung.
Noch einmal: Wir bekommen es.
Zuerst im Service-Scope gibt es Zugriff, in dieser Migrate-DB-Methode
eine Instanz des Game Store-Kontexts abzurufen oder zu erstellen.
Dann nutzen wir den DB-Kontext, um DB zuzugreifen und alle
Migrationen durchzuführen.
Nun, um das hier zu verwenden, gehen wir zurück zu unserem
Programm, das die C#-Datei ist.
Also gehen wir erneut zum Datei-Explorer.
Und diese Methode müssen wir nach der Erstellung unseres
Webanwendungsobjekts dort aufrufen.
Also machen wir das vielleicht hier in Zeile 15, bevor die
Anwendung gestartet wird.
Rufen wir einfach den Befehl 'app migrate db' auf.
Jetzt testen wir endlich unsere neue Logik im Praxistest.
Und dazu gehen wir jetzt wieder in den Dateiexplorer.
Und was ich jetzt tun werde: Meine Game-Store-DB-Datei zu löschen,
damit sie beim Start der Anwendung automatisch neu erstellt wird – so
wie unser Code es tun sollte.
Also klicken wir hier mit der rechten Maustaste darauf.
Lass uns jetzt bitte die Datei löschen; sie ist gelöscht.
Jetzt öffnen wir unsere Kommandozeile auf J. Ich werde das hier bereinigen,
und wir starten einfach die Anwendung.
Dann tippe ich dotnet, run, Enter und bestätige es.
Und wir können klar sehen, dass die Datenbankdatei automatisch erzeugt wurde.
Also ab jetzt müssen wir nun nur noch die neue Migration in
unseren Code einfügen, und beim Start der App wird sie automatisch
auf unsere Datenbank angewendet.
Eine weitere Sache, die ich an dieser Stelle gerne tun möchte, ist die Menge
des Loggings von EF Core zu reduzieren, das jedes Mal entsteht, wenn dieser
Migrationscode ausgeführt wird.
Wie man sieht, wird hier viel geloggt – hilfreich, um zu verstehen, was
hinter den Kulissen passiert –, doch wenn wir all dies ansehen, wird
es einfach doppelt so viel sein.
Jedes Mal, wenn wir die Anwendung starten.
Um die Protokollausgaben zu reduzieren, folgt Folgendes.
Wir stoppen die Anwendung einfach.
Strg+C wird mein Terminal schließen, und wir gehen zur JSON-Datei.
In diesem Kurs befasse ich mich nicht mit dem ASP.NET Core-Login.
Aber Sie sollten wissen: Sie können das Logging der verschiedenen Teile
der .NET- und ASP.NET Core-Bibliotheken durch Änderung des Log-Levels steuern.
Hier in der Website-JSON-Datei,
Hier sehen Sie eben, dass das standardmäßige Protokollierungsniveau
dem Informationsniveau entspricht.
Auch das Protokollierungsniveau der Bibliotheken, die zum Microsoft
.NET-Koordinatenraum gehören.
Wir können hier auch unsere eigene Einstellung für das Protokollierungsniveau
von Entity Framework und Core-Datenbankbefehl festlegen.
Also hier können wir Microsoft, dieses Entity Framework oder diese
Datenbank auswählen, diesen Befehl.
Und in diesem Fall wird Folgendes wirklich umgesetzt.
Wir reduzieren das Protokollierungs-Level so, dass wir ausschließlich
Meldungen im Protokoll sehen, die mindestens dem Warnlevel entsprechen.
Das bedeutet, Warnungen, Fehler und kritische Meldungen werden angezeigt,
während Informationsprotokollierung, Nachverfolgung oder
Entwicklungsnachrichten nicht angezeigt werden.
Ich gebe hier eine Warnung aus.
Das sollte die Logs in der Konsole senken.
Probieren wir es aus.
Gehen wir zurück in den Datei-Explorer.
Löschen wir Game-Store-TV.
Deshalb mag ich Esq Light, um das zu lernen, denn die Datenbank
lässt sich leicht löschen.
Also ist es weg.
Und jetzt kehren wir nun zum Terminal zurück.
Starten wir die App.
Wie man sieht, sind SQL-Anweisungen verschwunden.
Sie werden zwar ausgeführt, erscheinen aber nicht in den Logs, weil wir
die Protokollierung reduzieren.
Sie können das später ändern, falls nötig; aber im Rest des
Kurses sollte es funktionieren.
Jetzt ist es an der Zeit, unsere neue Datenbank an unseren Endpunkten zu nutzen,
damit alle Endpunkte stabil arbeiten.
Bevor wir das tun, brauchen wir vermutlich erst Daten in
der neuen, großzügigen Tabelle.
Wenn wir jetzt die Tabelle kurz prüfen, gehen wir zum SQL-Light-Explorer,
klappen ihn zu, und schauen dann in die großzügige Tabelle; vielleicht nehmen
wir sie hierher mit und testen später erneut, und alles funktioniert gut.
Wir werden schon sehen, dass der Tisch völlig leer ist.
Deshalb können wir über unsere Spiele-Endpunkte
jetzt keine Spiele erstellen.
Da der Fremdschlüssel bald verlangt, dass wir zuerst etwas
in der zugehörigen Tabelle haben.
Also, wir bauen keine Endpunkte, um unsere großzügige Tabelle
zu füllen; was wir tun können.
Fülle unsere Datenbank mit Beispieldaten.
Wenn die Anwendung läuft, befüllen wir sie mit Beispieldaten, die wir
später für Spiel-Endpunkte benötigen.
Also zeige ich dir, wie's geht.
Schließen wir das hier.
Lassen wir auch unseren Server jetzt stoppen.
Und gleich zurück zu unserer C#-Datei.
Lass mich schließen.
Andere Tabs gehen hierher zurück.
Lass uns den Teil finden, indem wir unser ES-Licht hinzufügen.
Hier.
Wir können außerdem Optionen der Add-ESCAL-Lichtmethode verwenden,
um auch die Datenbank zu sehen.
Sobald es sogleich erstellt wird.
Also, lass uns das machen.
Lass uns das wirklich in die nächste Zeile senden.
Lasst uns bitte das jetzt tun und einen weiteren Parameter hinzufügen.
Das wird unsere Optionenaktion sein.
Das ist also ein Delegat, der die Funktion bereitstellt, die nach der Erstellung der
Datenbank ausgeführt wird, damit wir die Datenbank ordnungsgemäß befüllen können.
Also lasst uns Optionen wirklich verwenden.
Und hier rufen wir die Optionen auf, die Seed-Verfahren verwenden.
Klammern, dies empfängt einen Parameter, der unser DV-Kontext sein wird.
Also Kontext, hier wird es einen weiteren Parameter geben, den wir
nicht verwenden werden, also lass ihn dort einfach mit einem Unterstrich
verwerfen, und dann liefern wir hier die eigentliche Logik, indem wir unsere
Abfrageklammern öffnen und schließen.
Und die Logik hier wird so aussehen: Falls kein Kontext
vorhanden ist, dieses konkrete Set.
Dies wird uns eines der DV-Sets im Datenbankkontext liefern, und dieses
konkrete Set wird das großzügige Set sein, das wir im weiteren Verlauf betrachten.
Okay.
Irgendwas, und bevor wir fortfahren, drücken wir bitte Strg.
Punkt bei Erzeugen, damit wir unsere Game-Store-API verwenden können, die
den Namensraum wirklich abbildet.
Okay.
Also falls wir nichts finden sollten.
In der großen Tabelle sollte dies der Fall sein.
Wenn die Datenbank gerade erstellt wird, führen wir die folgende Logik aus.
Wir werden den Kontext klar, ausführlich und eindeutig angeben, der Gen festlegt,
der Reichweite erweitert, und hier werden wir es schrittweise einführen,
zur besseren Nachvollziehbarkeit.
Unser erstes Spiel ist großzügig.
Dafür können wir das so machen.
Wir können doch eine neue Gen.
Legen wir zum Beispiel, ganz einfach, einen Namen fest.
Unser erster wird auf lange Sicht kämpfen und.
Und auf dieselbe Weise können wir auch einige weitere Genres einführen, die
unser Portfolio sinnvoll ergänzen und unseren Nutzern mehr Auswahl bieten.
Also werde ich sie hier zunächst nicht manuell eintippen, sondern
vorerst so belassen, dass sie hier vor Ort sichtbar bleiben.
Ich füge sie hier tatsächlich ganz einfach aus meinem Spickzettel ein.
Dort.
Also haben wir jetzt fünf Spiele, die bereit sind, mit einem
unserer kommenden Spiele in der Datenbank verknüpft zu werden.
Natürlich müssen wir uns auch daran erinnern, diese Informationen in der
Datenbank zu speichern, und wir können das tun, indem wir den DV-Kontext bzw.
Kontext aufrufen, der die SaveChanges-Methode ausführt,
wie hier gezeigt wird.
Super.
So mit diesem sollten wir nun bereit sein, die Datenbank zu sehen.
Wenn die App startet.
Lass uns das Terminal noch einmal öffnen.
Öffne Terminal und räume auf.
Lass uns mal net run starten.
Okay, und jetzt werfen wir schnell einen Blick in unsere Datenbank,
Contra Shift E. Werfen wir erneut hier einen Blick hinein, um den Inhalt
der großzügigen Tabelle zu sehen.
Klick dort hin, und tatsächlich übernehmen wir das hierher.
Jetzt sehen wir, dass unsere anfänglichen großzügigen Einträge vollständig
in die Datenbank übernommen wurden.
Datenbank läuft wie erwartet.
Nun, wie bei allem Übrigen auch, lasse ich diese Logik nicht direkt
auf dem gleichen Niveau wie C#, denn wieder einmal wird sie von zu viel
Logik aufgebläht, die die Datei größer macht und schwer zu verstehen ist.
Also tun wir Folgendes: Wir stoppen hier meinen Server und verschieben
all die Datenbanklogik in eine neue Erweiterungsmethode, damit wir hier
nur eine Zeile aufrufen müssen, um all diese Logik zu starten.
Also, dafür gehen wir zurück zu contrive E. Öffnen wir den Explorer,
gehen in die Daten und in unsere Daten-Erweiterungen, zur CS-Datei.
Denk daran, dass hier unsere DB-Migrations-Erweiterungsmethode
liegt; daher ist sie gut geeignet, eine Methode einzuführen.
Um sehr umfassend und ordnungsgemäß unsere Datenbankdienste
und auch unsere anfängliche Datenbefüllung zu registrieren.
Unter dieser Methode fassen wir daher eine neue hinzu, die wir Public Static
Void bei GameStoreDb nennen werden.
Diese wird unseren WebApplicationBuilder schrittweise und umfassend erweitern.
Und hier übernehmen wir einfach die gesamte Logik, einschließlich
unserer Verbindungszeichenfolge, und zwar bis hierher.
Lass uns doch einfach alles hier entfernen und es hierher rüberbringen, bitte.
Okay, lass uns unter Generate hier das C#-Steuerelement auswählen, damit
wir unsere Game Store API einführen.
Dieses Modell liegt im Geltungsbereich, und die Logik wurde nun vollständig
außerhalb von Program.cs verschoben.
Jetzt können wir wieder in das C#-Programm gehen und direkt danach.
Unser Ad-Validierungsaufruf; wir können jetzt builder.at GameStoreDB
aufrufen, was eine saubere Datei ergibt.
Nochmals können wir unnötige Using-Anweisungen entfernen,
um den Code sauberer zu halten.
Also läuft bisher alles gut.
Aber eine Sache ist zu beachten: Wenn Sie in die Daten-Erweiterungen zurückgehen,
die Cs betreffen, ist es so, dass wir diese hartkodierte Verbindungszeichenfolge
direkt in unserem C#-Code belassen.
Das ist wirklich nicht ideal, denn sobald wir versuchen, die Anwendung in
eine andere Umgebung zu verschieben, zum Beispiel in die Produktion, müssen wir
die Verbindungszeichenfolge direkt im Code vollständig ändern, damit sie in die
Produktion bereitgestellt werden kann.
Und falls wir wieder zur Entwicklung wechseln müssen, ändern wir es
zurück auf diesen lokalen String.
Das wird sicher fehlerhaft und problematisch.
Lass uns Pause machen, um mehr über das SVnet-Konfigurationssystem zu erfahren.
und wie es uns bei diesem hartkodierten String hilft
Zu diesem Zeitpunkt haben wir die Verbindungszeichenfolge fest in unseren
Anwendungscode eingebaut, um direkt mit unserer Datenbank zu kommunizieren.
Allerdings ist das nicht ideal, denn wenn wir die API später in eine andere
Umgebung verschieben, zum Beispiel in eine Cloud-Bereitstellung, wird die
Verbindungszeichenfolge anders sein und wir müssten zusätzlichen Code ändern.
Glücklicherweise gibt es wirklich bessere Orte, um die
Anwendungskonfiguration zu speichern.
Eine der beliebtesten Optionen in .NET Core, insbesondere
für die lokale Entwicklung.
Die appsettings.json-Datei, die alle Arten von Konfigurationsinformationen
im JSON-Format speichern kann.
Nun ist die appsettings.json-Datei eine Konfigurationsquelle; wie diese
gibt es weitere Konfigurationsquellen, die in .NET-Anwendungen unterstützt
werden, etwa Befehlszeilenargumente, Umgebungsvariablen, Benutzergeheimnisse
und sogar cloudbasierte Quellen wie Azure Key Vault.
Und das Tolle daran ist, dass SG-Net-Core seine Infos aus allen verfügbaren
Konfigurationsquellen in ein einziges Konfigurationsobjekt bündelt, das
die I-Schnittstelle implementiert.
Dieses Konfigurationsobjekt ist für Ihre beste API eben so leicht zugänglich,
dass es im Grunde nicht wissen muss, woher die Daten tatsächlich stammen.
In diesem Tutorial speicherst du deinen Verbindungsstring in
der Datei neben der Website.
Beachte, dass dies nur eine zulässige Option ist, da du keine
Zugangsdaten brauchst, um dich mit deiner SQLite-Instanz zu verbinden.
Für lokale Entwicklung: Falls Sie eine Datenbank-Instanz mit Zugangsdaten
verwenden, verwenden Sie bitte die User-Secrets-Konfigurationsquelle,
die durch den NET Core Secret Manager aktiviert ist.
Speichern Sie niemals Zugangsdaten in Ihrer Website,
insbesondere in dieser JSON-Datei.
Lass uns jetzt SAPI updaten, damit sie den Verbindungsstring aus JSON lesen kann.
Schauen wir uns an, wie man das ASP.NET Core-Konfigurationssystem verwendet, damit
die Verbindungszeichenfolge nicht mehr hart in unseren C#-Dateien codiert wird.
Fangen wir hier in appsettings.json an und klappen das zusammen.
Also führen wir hier unseren Verbindungsstring ein, indem
wir in dieser Datei einen gut bekannten Schlüssel verwenden.
Also öffnen wir hier nun einen weiteren Abschnitt und
nennen ihn Verbindungsstring.
Lass uns diesen Abschnitt öffnen und unsere Verbindungszeichenfolge
als Schlüssel-Wert-Paar verwenden.
Da dies die Verbindungszeichenfolge der Game Store-Datenbank ist,
können wir etwas Einfaches wie Game Store als Schlüssel verwenden.
Und dann für den Wert: Wir wollen dieselbe Verbindungszeichenfolge
verwenden, die wir bisher im Code nutzen.
Also führe ich Kontrastverschiebung E aus.
Um wieder in unsere Daten und Erweiterungen zu gelangen, diese CS-Datei;
Denk daran, unsere Verbindungszeichenfolge liegt hier in der GameStore-DV-Methode.
Es ist hier; kopiere es.
Und ich füge es hier ein.
So speicherst du deine Verbindungszeichenfolge in der Config,
damit das .NET Core-Konfigurationssystem sie einfach lesen kann.
Aber klar, wir müssen jetzt wirklich Data Extensions ändern,
damit wir das System nutzen können.
Dafür müssen wir Folgendes tun.
Also hier ersetzen wir dies durch einen Aufruf an den Builder, jene Konfiguration,
die die Verbindungszeichenfolge erhält, und der Parameter zu dieser Methode wird
der Schlüssel der Verbindungszeichenfolge sein, den du gerade definiert hast.
Also kehren wir nun zum JSON zurück; dieser Schlüssel wird 'game store' sein.
Also kopieren wir das mal.
Hierher zurück.
Wir fügen es dort ein.
Und die Zeile beenden.
Das ist, was Sie tun müssen, um Ihre Konfiguration aus Apps-Datei zu lesen
und zu beweisen, dass es funktioniert.
Setzen Sie hier mal einen Haltepunkt in meiner Zeile.
Starten wir die App und prüfen, ob wir den Verbindungsstream lesen können.
Drücke F5.
Hier sind wir.
Lass uns das hier zusammenfassen, vielleicht auch dieses hier.
Und wenn wir mit der Maus über die Verbindungszeichenfolge fahren, sehen
wir, dass die Verbindungszeichenfolge tatsächlich von Abta Jason gelesen wurde.
Hier braucht man Verbindungsstring nicht mehr hart zu kodieren.
Ich klicke auf Play, und die App startet normal.
Allerdings ist die Stärke des Konfigurationssystems, dass du
die Verbindungszeichenfolge nun in jeder Umgebung nach Bedarf
überschreiben kannst, etwa in einer Produktionsumgebung, und dir zeigen
kannst, wie das funktionieren könnte.
Lass uns Folgendes tun.
Lass uns einfach diese Detox-Sitzung beenden.
Lass uns Terminal öffnen.
Ich wechsle hier zu einem echten Terminal.
Öffne ein Terminal neu.
Vielleicht schließen wir es mal.
Und machen wir Folgendes.
Lass mich maximieren.
Wir legen jetzt den Verbindungsstring als Umgebungsvariable fest.
Da ich hier PowerShell verwende, besteht der Weg darin, hier einen M-Aufruf mit
dem Namen der Umgebungsvariable anzugeben.
Jetzt soll hier ein Name verwendet werden, bitte; lass es kurz zusammenfassen,
denn der Name wird Jason sein.
ist dazu fähig
Folge einer gut bekannten Hierarchie von Namen, um Dinge
in die Konfiguration abzubilden.
In diesem Fall kann ich daher den Namen meiner Umgebungsvariablen mit dem Wort
Verbindungszeichenfolge so beginnen.
Danach trenne ich diesen Schlüssel vom Unter-Schlüssel, indem ich zwei
Doppelpunkte verwende, und dann können wir den nächsten Namen platzieren.
Im Konfigurationsschlüssel wie hier setze ich dann ein
Gleichheitszeichen und anschließend den eigentlichen Wert ein, richtig?
Ich kopiere den Wert.
Hier, aber diesmal, um zu beweisen, dass das tatsächlich funktionieren wird,
werde ich den Namen der Datenbank ändern.
Also stellen wir uns vor, dass wir uns jetzt in der Produktion befinden.
Wir legen eine Umgebungsvariable für eine andere Datenbank fest.
Nennen wir sie production db, und drücke Enter.
Wenn das funktioniert, sollten wir am Ende diese neue Datenbank erhalten,
wenn wir die Anwendung diesmal mit einem einfachen Aufruf von dotnet run ausführen.
Also wechseln wir in unser Game Store API-Verzeichnis hinein, und bevor
wir dot und Run ausführen, öffnen wir vielleicht unseren Datei-Explorer-Fenster,
um zu prüfen, dass unsere Datenbank bisher noch Game Store db heißt.
Aber jetzt, wenn wir .NET Run ausführen, während hier diese
neuen Umgebungsvariablen für eine passende Konfiguration
gesetzt sind, drücken wir Enter.
Und was wir sehen, ist, dass eine brandneue Datenbank – unsere
Produktionsdatenbank – jetzt erstellt wird, weil die Anwendung
nun glaubt, dass dies der neue Wert für unsere Konfiguration ist.
Beachten Sie, dass sie die Migration sogar noch einmal angewendet hat.
Es ist eine neue Datenbank.
Also nur dadurch, dass man diesen brandneuen Wert im Terminal als
Umgebungsvariable setzt, konnten wir die Konfiguration vollständig ändern, ohne
jemals unseren C#-Code anfassen zu müssen.
Der C#-Code ist derselbe, den Sie gesehen haben, der die Konfiguration liest.
Er weiß wirklich nicht, woher die Konfiguration kommt.
Und genau das macht das ASP.NET Core-Konfigurationssystem sehr
leistungsfähig und flexibel, sodass derselbe Code in vielen
Umgebungen funktionieren kann.
Nun, da ich diese Umgebungsvariable in meiner Terminal-Sitzung gesetzt
habe, wird sie verschwinden, sobald ich das Terminal beende.
Und zum Bestätigen gehen wir zurück und öffnen Terminal erneut.
Lass uns Strg-C verwenden, um die Anwendung zu stoppen.
Lass uns dieses Terminal einfach schließen.
Gehen wir zurück in den Dateiexplorer und löschen diese
neue Produktionsdatenbankdatei, die wir erstellt haben.
Löschen.
Es ist weg.
Und jetzt, falls ich mein Terminal erneut öffne, gehen wir wieder hinein,
API speichern und dann ausführen.
Die App wird jetzt starten, aber sie wird wieder aus unserer
JSON-Datei lesen, richtig?
Sie wird hier lesen, denn es gibt keine Umgebungsvariable mehr.
Und man sieht auf der linken Seite, dass wir wieder in der Instore-Datenbank sind.
Es gibt keine Produktionsdatenbank mehr.
Und damit sind wir mit dem Konfigurationsteil der Anwendung
fertig, und es ist Zeit, die Vorteile aus unserer neuen Datenbank über
unsere API-Endpunkte zu nutzen.
Bevor wir das tun, müssen wir ein wirklich sehr wichtiges
Konzept in ASP.NET Core lernen,
Es ist als DI-System bekannt.
Machen wir hier bitte eine kurze Pause, um mehr darüber zu erfahren.
Um zu verstehen, was Abhängigkeitsinjektion ist,
betrachten wir zwei Klassen: meinen Service und meinen Logger.
Mein Service verwendet Logging, diese Methode meines Loggers, um Meldungen
in eine Datei zu schreiben, wann immer mein Service eine Operation ausführt.
Da mein Service einige Funktionen meines Loggers nutzt, wie das Logging,
bleibt diese Methode bestehen, ja
Wir sagen, dass mein Logger Abhängigkeit von meinem Dienst ist.
Nun, damit mein Dienst in der Praxis meinen Logger verwenden kann, erstellt
er im Konstruktor eine Instanz meines Loggers, und danach kann er
beginnen, diese Methode aufzurufen.
I. Auf den ersten Blick scheint dies hier kein Problem zu sein, aber
bedenken Sie doch bitte, was geschieht, wenn die Autoren meines Loggers es
leicht verändern, sodass ein neues Dateischreiber-Objekt im Konstruktor
übergeben werden muss, weil dort jetzt die Ausgabedatei definiert ist.
Die notwendigen Änderungen wirken einfach umzusetzen, zeigen
aber einige wichtige Probleme.
Mein Dienst ist äußerst eng an mein Logdatei-System gebunden, sodass sich
jedes Mal, wenn sich mein Log ändert, auch mein Dienst angepasst werden muss – so
wie hier, als der Konstruktor begann, eine Datei-Schreiber-Instanz zu verlangen.
Mein Dienst muss wissen, wie man die My-Logger-Abhängigkeit aufbaut
und konfiguriert, wie hier am Dateischreiber-Objekt, das auch mit
einer passenden Datei eingerichtet werden muss, um die Ausgaben zu speichern.
Das macht es schwer, meinen Dienst zu testen, da Unit-Tests meinen Logger nicht
mocken oder seine Ausgabe stoppen können.
Diese Log-Datei wird immer erzeugt, was die Tests verlangsamen würde.
Falls die Tests Zugriff auf einen Ort zum Schreiben von Dateien haben,
gibt es glücklicherweise eine bessere Lösung: Abhängigkeitsinjektion.
Gehen wir zurück zu meinem Service, und es handelt sich um meine Logger-Abhängigkeit.
Mein Service protokolliert diese Methode weiter; diesmal wird der Logger nicht
explizit von meinem Service erzeugt.
Stattdessen wird mein Logger als Konstruktorparameter übergeben.
So muss mein Service nicht wissen, wie der Logger aufgebaut oder
im Detail konfiguriert wird.
Es nimmt es einfach entgegen und kann es sofort auch verwenden.
Aber wenn mein Dienst den Logger nicht erzeugt, wer tut das denn dann?
Nun, ASP.NET Core stellt den IServiceProvider bereit, der als
Service-Container bezeichnet wird.
Ihre Anwendung kann meinen Logger und alle anderen Abhängigkeiten während
des Startvorgangs beim IServiceProvider registrieren, was typischerweise in Ihrem
Programm, in dieser CS-Datei, geschieht.
Dann später, wenn eine neue HTTP-Anfrage eingeht und Ihre Webanwendung eine Instanz
meines Dienstes benötigt, erkennt der Service-Container diese Abhängigkeiten,
löst sie auf, konstruiert sie und injiziert sie über den Konstruktor
in eine neue Instanz meines Dienstes.
Dies eröffnet Ihrer Anwendung eine Vielzahl praktischer, messbarer,
sicherer und vielseitiger Vorteile.
Zu Beginn bleibt mein Dienst von Änderungen an seinen
Abhängigkeiten wirklich unberührt.
Es ist egal, wie oft sich der Konstruktor meines Logs ändert; auch
kein Grund, meinen Dienst zu ändern.
Außerdem wird mein Dienst keine Instanzen meines Loggers erstellen,
daher braucht er nicht zu wissen, wie man ihn baut oder einstellt.
Und falls Ihre Anwendung Minimal-APIs nutzt, lassen sich Abhängigkeiten auch
als Parameter an API-Endpunkte injizieren.
Ich.
Aber wann genau sollte ich als Dienstanbieter neue Instanzen erstellen?
Wir wissen, dass beim Start Ihre App die Abhängigkeiten wie meinen Logger
registrieren wird, und später, wenn eine HTTP-Anfrage eintrifft, wird
der Serviceanbieter automatisch eine Instanz meines Loggers in eine neue
Instanz Ihrer Klasse injizieren.
Mein Dienst in diesem Beispiel; was nicht ganz klar ist, ist, was passiert,
wenn nun eine neue Anfrage hier ankommt?
Soll der Dienstanbieter für die neue Anfrage eine brandneue
Logger-Instanz erstellen, oder soll er dieselbe Instanz wiederverwenden?
Was passiert, wenn ein anderer Dienst, der ebenfalls von meinem Logger
wirklich abhängig ist, im Zuge einer neuen Anfrage erstellt werden muss?
Gib meine Logger-Instanz aus, oder eine neue.
Die Antwort darauf liegt in der Lebensdauer des Dienstes.
Anders gesagt: Wie lange jede Instanz auch leben soll.
Es gibt drei Dienstlebensdauern: transient, scoped und singleton.
Zurzeit richten wir unseren Fokus jedoch gezielt auf scoped, denn genau auf diese
Weise registrieren Sie Ihren DbContext sicher und korrekt in Ihrer Anwendung.
Angenommen, mein Logger ist eine Klasse, die einen Zustand verfolgt,
der von mehreren Klassen, die an einer HTTP-Anfrage beteiligt sind,
gemeinsam genutzt werden muss.
In diesem Fall würden Sie meinen Logger hier mit der AddCode-Methode registrieren,
sobald eine HTTP-Anfrage eintrifft.
Der IServiceProvider wird auflösen, konstruieren und eine Instanz meines
Loggers in meinen Dienst injizieren.
Aber falls es einen weiteren Dienst gibt, der an derselben HTTP-Anfrage
mitwirkt und ebenfalls von meinem Logger abhängt, erhält dieselbe
Instanz dieser Abhängigkeit.
Falls jedoch eine neue HTTP-Anfrage eingeht, erzeugt der Dienstcontainer
eine, injiziert, eine völlig neue Instanz meines Loggers, die völlig
unabhängig von der vorherigen Instanz ist.
Daher werden Lebensdauer-Services pro HTTP-Anfrage einmal erzeugt und
innerhalb dieser Anfrage wiederverwendet.
Kehren wir nun zum Code zurück und betrachten das Lebenszyklus-Verhalten,
indem wir den DB-Kontext in unsere API-Endpunkte injizieren.
Lass uns sehen, wie man unseren DB-Kontext mit unseren API-Endpunkten nutzt,
indem man DI-System effektiv verwendet.
Also schauen wir uns unsere Endpunkte und die Spiele-Endpunkte an, nehmen wir uns
das einen Moment lang vor, und beginnen wir einfach mit dem POST-Endpunkt,
dem Endpunkt, der Spiele erstellt.
Scrollen wir hier nach unten zu unserem Map-Aufruf.
Um unseren DB-Kontext in diesen Endpunkt einzuführen, müssen wir ihn
bitte lediglich als neuen Parameter in unserem Handler hinzufügen.
Also nach unserem neuen DTO können wir dort ganz einfach den Game Store-Kontext
und den DB-Kontext hinzufügen.
Machen wir es hier, bitte, damit wir unseren Game Store verwenden können.
Erzeuge bitte einen pi.data-Namensraum.
das trägt dazu bei, dass der Service-Container läuft
Löst Konstrukte auf und injiziert gleichzeitig eben eine neue Instanz des
Game Store-Kontexts in den Endpunkt.
Aber wo wurde der C#-Kontext eigentlich dafür registriert?
Gehen wir schnell zurück in unser Programm, in diese CS-Datei.
Und erinnern Sie sich daran, dass wir hier diesen Aufruf haben, der in der
Game Store-Datenbank aufgerufen wird.
Ich werde auf diesen hier klicken und F12 drücken, um zu
sehen, was dort vor sich geht.
Hier sollten wir uns daran erinnern, dass wir nach dem bloßen Abrufen
der Verbindungszeichenfolge diesen Aufruf in SQLite des Typs
Game Store Context ausführen.
Dies ist der exakte Moment, in dem wir den R-Db-Kontext im
Service-Container zur Vorbereitung auf die Abhängigkeitsinjektion registrieren.
Und eines sollten Sie realisieren: Dieser Aufruf unterscheidet sich
nicht allzu sehr davon, etwas Ähnliches wie builder.Services zu
erstellen, das im Gültigkeitsbereich des GameStore-Kontexts liegt.
Also registriert hier SQLite wirklich unseren Datenbank-Kontext mit einer
Scoped-Service-Lebensdauer, ganz genauso, wie es Scope heute tun würde.
Aber warum sollten wir den DB-Kontext als Scoped-Dienst registrieren, statt
eines Singleton-Dienstes oder eines transienten Dienstes vielleicht.
Es muss verstanden werden.
Lass uns kurz reden.
Ich entferne das hier und schreibe Kommentare, um es zu erklären.
Der R‑DB-Kontext hat eine Scoped-Lebensdauer, denn diese
Lebensdauer im Scope sorgt dafür, dass für jede einzelne Anfrage eine
neue, frische Instanz des Kontexts erstellt und wieder verworfen wird.
Wenn Sie kurz zu den Game-Endpunkten zurückgehen, müssen Sie
verstehen, dass dies der Fall ist.
Jedes Mal, wenn Ihr Map-Post-Endpunkt aufgerufen wird, wird eine brandneue
Instanz von GameStoreContext erstellt, und sie besteht nur bis
zum Ende der jeweiligen Methode.
Sobald wir diesen Map-Endpunkt verlassen, wird der Kontext
des Spielegeschäfts zerstört.
Und wenn ein Aufruf an Map-Endpunkt oder an einen anderen Endpunkt eingeht, wird
eine Instanz des Kontexts neu erstellt.
Aber was ist das, was wir so wollten?
Na ja, halt.
Deswegen.
Datenbankverbindungen sind eine begrenzte und relativ teure Ressource,
daher wird der Umfang und die Lebensdauer des Kontextes dafür
sorgen, dass die Verbindungen effizient geöffnet und geschlossen werden.
Der Datenbankkontext
Ist nicht thread-sicher, daher könnte eine einzige DB-Kontext-Instanz
über mehrere Anfragen hinweg zu gleichzeitigen Problemen führen.
Indem man pro Anfrage eine DbContext-Instanz verwendet, ist es
leichter, Transaktionen zu verwalten und die Datenkonsistenz über eine
einzige Arbeitseinheit sicherzustellen, ohne Störungen durch andere Anfragen.
Und außerdem kann die Nutzung derselben DB-Kontextinstanz über einige Anfragen
hinweg zu mehr Speicherbedarf führen, weil der Kontext Änderungen an Entitäten
über seine Lebensdauer verfolgt.
Durch die Verwendung einer Scoped-Lebensdauer bleibt jeder DB-Kontext
kurzlebig, was Speicherbedarf reduziert und Leistung wirklich verbessert.
Das sind doch die Hauptgründe, warum.
Der DbContext ist mit einer Scoped-Lebensdauer registriert, und
Sie sollten das beachten, wenn Sie den DbContext in Ihren APIs nutzen.
Jetzt kehren wir in unsere Spiel-Endpunkte zurück.
Und schau, wie man diesen TV-Kontext nutzt.
Und zuerst hier tun.
Es geht darum, eine neue Instanz zu erstellen, nicht von unserem Spiel,
wie bisher, sondern von unserem neuen Spielmodell, das wir wirklich nutzen,
um es in der Datenbank zu speichern.
Also lass uns das hier alles löschen und stattdessen unser Spiel erstellen,
indem wir Game Game einfach so machen.
Und dafür lass uns hier einfach so vorgehen, damit wir unseren
GameStore.API.Models-Namespace korrekt einführen können.
Und das wird dort unsere neue, wirklich neue Instanz sein.
Und hier wird die erste Eigenschaft, die festgelegt werden soll, tatsächlich
unser ganz persönlicher Name sein.
Also können wir den Namen auf 'new game' setzen.
Gib bitte den Namen ein und achte darauf, dass wir die ID nicht angeben, denn der
Datenbankanbieter wird dafür letztlich verantwortlich sein, wie eine eindeutige
Kennung für das Spiel erzeugt wird, sobald das Spiel dort erstellt worden ist.
Als Nächstes möchten wir unsere Generierungs-ID festlegen, die
unser künftiges, neues Spiel wäre.
Diese Generierungs-ID.
Allerdings sieht man, dass wir in unserem Create-Game-DTO noch
keine Generierungs-ID haben, oder?
Es ist nur Generierung, und das müssen wir unbedingt ändern,
damit das DTO vollständig wird.
Wenn wir ins Create-Game-DTO zurückgehen, erinnern wir uns daran, wie wir unsere
Generierung hier definieren, richtig?
Und das klappt nicht so richtig.
Wenn unsere Frontend-Kunden
Schick POST an unseren Endpunkt
Weil die eindeutige Kennung des Gewählten Generators das ist, was sie senden.
Frontend-Oberfläche.
Lass uns das ändern.
Eine Identifikationsnummer erzeugen.
Und in Bezug auf unsere Datenannotation ändern wir vielleicht alle davon in einen
gültigen Bereich für unsere Generatoren.
Von eins, zwei, sagen wir fünfzig, damit wir zumindest zu Beginn potenziell bis
zu fünfzig Generatoren haben könnten.
Und damit kehren wir zu den Gewinnpunkten zurück, zu jenen
wichtigen, zukunftsorientierten Zielen, die uns klare Ergebnisse anzeigen
und die Richtung deutlich vorgeben.
Und jetzt können wir hier ein neues Spiel definieren, um eine eindeutig
identifizierbare ID zu erzeugen, und wir fahren fort mit dem Preis
dieses neuen Spiels, der festgelegt wird, damit alles konsistent bleibt.
Und das Veröffentlichungsdatum des neuen Spiels ist der festgesetzte Termin, an
dem es offiziell veröffentlicht wird.
So definiert es uns.
Das Spielmodell, das in die Datenbank eingefügt werden soll.
Aber wie fügen wir es tatsächlich in die Datenbank ein?
Nun, das läuft so, dass wir dafür unseren DB-Kontext verwenden müssen.
Also statt dieses Vorgehens setzen wir künftig auf den DB-Kontext statt
auf Spiele, die etwas hinzufügen.
Und hier präsentieren wir unser neues Spielmodell.
Äh.
Beachten Sie jedoch, dass diese Zeile das Spiel nicht tatsächlich
in die Datenbank sendet.
Sie veranlasst lediglich Entity Framework Core, damit es beginnt, zu verfolgen,
dass ein neues Spiel in die Datenbank eingefügt werden muss, um den DV-Aufruf
auszuführen und das Spiel zu speichern.
Was Sie tun möchten, ist Kontext dafür zu geben, dass Änderungen gespeichert werden.
Dies übersetzt alle Gemäldenänderungen im DB-Kontext.
Änderungstracker.
In SQL-Anweisungen, die die Datenbank künftig verstehen wird.
Also ist das Spiel damit gespeichert, aber natürlich müssen wir dem
Client noch etwas zurückgeben.
Und wie wir hier sehen können, befindet sich unsere
Route-Methode 'created_at' hier.
Sie enthält hier unsere Spielinstanz vollständig und sichtbar, hier drüben.
Allerdings ist das zu diesem Zeitpunkt nicht ideal, denn daran
erinnert man sich: Das hier gezeigte Spiel gehört nicht mehr zu ETO.
Es ist unser tatsächliches Spielmodell, das gerade in der
Datenbank gespeichert wurde.
Und aus guten Gründen möchten wir die internen Details des Systems weder unseren
Anrufern noch unseren Kunden offenlegen.
Denn das würde es später erschweren, unser internes Datenmodell zu ändern,
ohne unsere Kunden zu beeinträchtigen.
Also statt unser Spielobjekt zurückzugeben, tun wir das.
Gib erneut DTO zurück.
Welche DTO sollen wir hier eigentlich verwenden?
Nun, es könnte dasselbe sein, das wir vorher benutzt haben,
also schauen wir kurz darauf.
Gehen wir in die DTS, und jene war das Game-DTO.
Das ist das, was wir zurückgegeben haben.
Allerdings wird dieses hier nicht ganz funktionieren, denn wie man
sehen kann, enthält es tatsächlich 'degenerate' als Zeichenkette,
im Gegensatz zu einer Ganzzahl.
Also statt dieses zu verwenden, lassen wir es vorerst einfach dort stehen und
legen los, ein neues DTO zu erstellen.
Ich kopiere das hier und füge es dort als Kopie ein.
Und wir benennen dieses Neue als Game details, DTO.
Okay, also das hier ist Game details, DTO.
Lass mich das entfernen.
Lass uns das zusammenlegen und hier die richtige Benennung vornehmen.
Game Detail C#, TO.
Und natürlich besteht der Unterschied darin, dass dieser
hier etwas zurückgeben wird.
Und ich werde eine ID generieren.
Und jetzt, da wir das hier haben, können wir wieder in unsere
Spiel-Endpunkte zurückkehren.
Und nach unserem sicheren Änderungsaufruf können wir Spieldetails definieren.
DTO, nennen wir es Game-DTO.
Es wird ein neues DTO sein, okay.
Lass uns bitte, gemeinsam, Klammern öffnen und wieder schließen.
Und hier möchten wir ganz bewusst unsere Game-ID angeben.
welches übrigens zu diesem Zeitpunkt nach Aufruf von Safe changes wird
diese ID bereits den automatisch generierten Wert für die Spiel-ID haben.
Es ist sinnvoll, jetzt die ID zu verwenden.
Danach geben wir den vollständigen Namen unseres Spiels an.
Generiere diesen Namen bitte jetzt.
Das Spiel, dieser Preis betrifft das Ende des Spiels.
Bitte gib außerdem das Veröffentlichungsdatum an.
Dann kopieren wir diese Game-DTO-Instanz einfach erneut, und wir verwenden sie für
unseren Aufruf der Route 'created_at'.
Hier, bitte.
Legen wir sie hierher, statt in das Spiel.
Wir fügen sie außerdem als Payload dieser POST-Anfrage hinzu, äh, zur Rückgabe.
Also verwenden wir sie hier direkt, Game-DTO, und zwar
jeweils hier, bitte nochmals.
Und damit ist unser POST-Endpunkt gänzlich darauf umgestellt worden,
tatsächlich unseren DB-Kontext zu verwenden, um das Speichern von
Spielen in der Datenbank zu starten.
Es ist jetzt gut, das auszuprobieren.
Öffnen wir doch unsere Terminals.
Ich drücke hier Strg-J.
Ich werde umschalten auf
Und speichere API.
Ich mache gleich einen Probelauf.
Okay, lass uns das hier jetzt bitte für einen Moment einfach mal
kurz schließen und danach unsere HTP-Datei für Spiele öffnen.
Erinnern wir uns daran, dass hier unser POST-Aufruf vorhanden ist, richtig?
Also hier ist der POST-Aufruf, um ein Spiel zu erstellen.
Aber natürlich besteht das Problem darin, dass es bisher immer
noch als String verwendet bzw.
erzeugt wird.
Also steht hier Platformer.
Wie uns allen bekannt ist, ist das etwas, das wir nicht mehr tun können.
Wir müssen die erzeugte ID liefern.
Also sollte dies die erzeugte ID sein.
Aber was ich hier so getan habe.
Wir müssen das herausfinden, indem wir kurz in unsere DB schauen.
Also klicken wir erneut auf Game Store-Dev.
Wählt bitte eine offene Datenbank aus.
Geht in unseren ES Light Explorer und klickt hier auf den
Playknopf, um den Inhalt unserer Allgemeinen Tabelle zu sehen.
Auf der rechten Seite sehen wir unsere aktuellen Generäle in der Datenbank.
Dem Platformer-Generator ist wirklich die Nummer drei zugeordnet, richtig?
Platformer ist Nummer drei.
Lass uns diese Drei verwenden, um unser Spiel zu machen.
Schließen wir das hier und setzen die Drei hier.
Und jetzt bricht es kurz zusammen.
Lasst uns hier auch unseren Preis ändern.
Das ist zu teuer.
Das.
Jetzt senden wir eine Anfrage und schauen, ob wir das Spiel in
die Datenbank aufnehmen können.
Also klicken wir auf 'Anfrage senden' – und die Anfrage war erfolgreich.
Wir können sehen, dass 201 erstellt wurde.
Wir sehen.
Hier unten wurde ein Spiel erzeugt.
Und wichtig: wie ich schon sagte, sehen wir, dass eine eindeutige
Kennung für unser Spiel von SQLite bereitgestellt wurde.
Wir mussten sie nicht angeben.
Es ist das Standardverhalten vieler Datenbanken, automatisch
eine ID zu erzeugen.
Zu Ihren Unterlagen, nach einer Sequenz.
Nun möchten wir wirklich bestätigen, dass das Spiel in der Spieletabelle existiert.
Also bitte schließen wir Strg-Shift-E.
Ich kehre nun wirklich in unseren Escalate-Explorer zurück.
Klicken wir hier bitte mal auf den Pfeil der Spieltabelle.
Klicken wir dort, und wenn wir das kurz minimieren und dorthin
verschieben, sehen wir, dass das Spiel in der Datenbank erstellt wurde.
Unser Folgeanruf war tatsächlich ein echter Erfolg.
Schließen wir das.
Gehen wir zurück zu unseren Spiel-Endpunkten.
und bevor wir beginnen, den Rest unserer Endpunkte im Game Store-Kontext zu nutzen,
Ich.
Es gibt noch ein weiteres Konzept, das wir lernen müssen, das ist
das asynchrone Programmiermodell.
Lass uns hier kurz pausieren.
Mehr über Async-Programmierung lernen.
Um asynchrone Programmierung zu verstehen, betrachten wir ein typisches
Frühstücksszenario als Beispiel im Alltag.
Nehmen wir an, du erhitzt deine Pfanne ein paar Minuten, und wenn
sie heiß ist, brätst du dort Eier.
Außerdem möchten wir zum Frühstück auch etwas Brot haben; nachdem die
Eier fertig sind, holen wir den Toaster heraus und rösten das Toastbrot.
Dann, wenn das Brot fertig ist, belegen wir es mit Marmelade oder Erdnussbutter.
Schließlich wäre unser Frühstück ohne Saft nicht vollständig, also
gießen wir etwas Orangensaft nach.
Insgesamt hat es uns etwa dreißig Minuten gedauert, unser Frühstück zuzubereiten.
Aber ist das wirklich so, wie du dein Frühstück an einem Werktag zubereiten
würdest, wenn du oft in Eile bist, vielleicht würdest du dann das hier tun.
Du erhitzt deine Pfanne, und währenddessen fängst du ebenfalls
eben an, deinen Atem zu rösten.
Und während das geschieht, kannst du vielleicht auch
deinen Orangensaft einschenken.
Schließlich, wenn die Pfanne bereit ist, gehst du zurück, um
zu essen und deine Eier zu braten, und sobald das Brot geröstet ist,
gehst du zurück und bestreichst es mit Marmelade oder Erdnussbutter。
Wenn du so vorgehst, bist du deutlich schneller fertig – sagen wir mal
15 Minuten –, und den Rest der Zeit kannst du dann dein Frühstück genießen.
Wenn man diese beiden Arten vergleicht, wie man sein Frühstück zubereitet, sagen
wir, dass der erste Ansatz synchron ist, da man keinen neuen Auftrag beginnt,
bevor der vorherige abgeschlossen ist.
Der zweite Ansatz hingegen ist asynchron, da man nicht darauf wartet,
dass eine Aufgabe abgeschlossen ist, bevor man mit der nächsten beginnt.
Hier beginnst du so viele Aufgaben, wie du kannst, und schließlich richtest du
deine Aufmerksamkeit auf Aufgaben, die für dich bereitstehen, damit du mit der
nächsten Aufgabe weitermachen kannst.
Auf ähnliche Weise können Sie in ASP.NET Core-Anwendungen
asynchrone Programmierung einsetzen.
Wenn ein Client eine Anfrage an Ihren Webserver sendet, möchten Sie die Anfrage
in Ihrem Endpunkt asynchron verarbeiten.
Damit dein Code, der Webserver, sofort wirklich frei ist, mit der Bearbeitung
der nächsten Anfrage zu beginnen.
Wenn dein Endpunkt einen asynchronen Aufruf startet, etwa an deinen
DB-Kontext, und dieser wiederum Daten asynchron aus der Datenbank anfordert,
hat der Webserver bereits begonnen, die nächste Anfrage zu bedienen.
Auch asynchron.
Wenn die Datenbank schließlich die angeforderten Daten liefert, setzt der
Kontext der Datenbank die Arbeit fort und sendet die Daten an den Endpunkt
zurück, der dann die Arbeit fortführt, Objekte in Details umwandelt und die Daten
an den Webserver zurücksendet, der auf die Clientanfrage der Region antwortet.
Danach setzt die Anwendung das asynchrone Starten von Aufträgen fort und nimmt
die Arbeit nun falls nötig wieder auf.
Wie Sie sehen können, bringt das asynchrone Programmiermodell
mehrere Vorteile.
Ihre Anwendung erzielt eine bessere Leistung, da blockierende Aufrufe
vermieden werden und Ressourcen freigegeben werden, damit sie
andere Aufgaben übernehmen können, was zu einer insgesamt
besseren Reaktionsfähigkeit führt.
Sie können Ihre Anwendung besser skalieren, weil sie mehrere Anfragen
und Benutzer gleichzeitig verarbeiten kann, ohne durch das Warten auf
I/O-Operationen blockiert zu werden.
Außerdem ermöglichen die Schlüsselwörter async und await eine einfache und
intuitive Methode, asynchronen Code zu schreiben, statt sich direkt
mit Threads und Callback-Funktionen herumschlagen zu müssen.
Jetzt, da du das asynchrone Programmiermodell und seine Vorteile
verstehst, schauen wir uns an, wie man es in unserer ASP.NET
Core-Anwendung einsetzen kann.
Eine Sache, die wir wirklich verstehen müssen, bezüglich der Art und
Weise, wie wir unsere API-Endpunkte implementiert haben, insbesondere unseren
POST-Endpunkt hier, ist, dass zu jeder gegebenen Zeit genau ein einzelner
Thread für die Ausführung dieses Endpunkts zugewiesen wird, richtig?
Also läuft alles, was in diesem Endpunkt programmiert oder codiert
ist, in exakt einem Thread ab.
Und wenn Sie es so ausführen, ist das der synchrone Weg, den Code auszuführen.
Dieser Thread kann nie an die Laufzeitumgebung zurückgegeben
werden, damit diese nichts anderes tun kann, oder doch?
Die Laufzeit ist darauf festgelegt, dass wir den Code vollständig abschließen,
bevor diese Ressource zurückgegeben wird.
Deshalb wechseln wir zum asynchronen Programmiermodell.
Damit wir nur so viel Arbeit erledigen, wie nötig.
Und wir haben alle Ressourcen wieder in die Laufzeit zurückgegeben,
damit sie etwas damit anfangen können, bis wir bereit sind,
mit unserem Code weiterkommen.
In dieser Methode schauen wir auf Zeile 60, wo wir Safe Changes aufrufen.
Dies ist die Zeile, in der wir mit der Datenbank sprechen.
Alle SQL-Befehle, die nötig sind, um unser Spiel zu speichern.
Dies ist eine Lage, in der wir aus unserem Prozess aussteigen und auf
eine externe Ressource – die Datenbank – zugreifen müssen, die möglicherweise
Zeit braucht, um zu antworten.
Die lokale Box ist etwas schneller, doch in der Produktion
könnte eine Cloud-Datenbank gehostet sein, was Zeit kostet.
Solange das passiert, können die Ressourcen dieser Bedrohung nicht in
die Laufzeit zurückgeführt werden.
Daher schalten wir auf das asynchrone Ausführungsmodell
um, um Ressourcen freizugeben.
Beachten Sie nun die Rückgabe der Änderungen.
Derzeit gibt es nur eine Ganzzahl zurück, die die Anzahl der Datensätze beschreibt,
die in der Datenbank gespeichert wird.
Und was du bei vielen Methoden wie dieser merkst, ist, dass es meist eine asynchrone
Version der Methode gibt, wie diese hier zum Beispiel; sie ändert sich asynchron.
Das wird nicht mehr nur eine Zahl zurückgeben, sondern eine
andere: eine Aufgabe, richtig?
Eine Aufgabe vom Typ in diesem Fall.
Das öffnet die Tür dazu, damit nicht nur eine synchrone Nummer zu empfangen.
Eine Aufgabe, der man Gewicht geben kann, und die nach
Abschluss weitere Arbeit zulässt.
Nun, da dies jetzt eine Aufgabe zurückgibt, können wir den Rest des Codes
nicht einfach ausführen, wie er jetzt ist.
Denn wenn Sie diese Methode aufrufen,
Du wartest nicht mehr darauf, dass in diesem Vorgehen alles fertig wird.
Du bittest sie nur darum.
Fang mit der Arbeit an; die Aufgabe kommt sofort zurück, und der Code läuft weiter.
Und wenn du nicht wartest, bedeutet das, dass dieser Code schon läuft und sogar
ein Ergebnis liefert, bevor Änderungen in der Datenbank gespeichert sind.
Also gibt es eine Möglichkeit, damit umzugehen, zum Beispiel; es gibt mehrere
Wege, aber eine davon ist die, dass du das tun könntest und damit fortzufahren.
Und dann könntest du hier einen Ausdruck öffnen, der die Aufgabe entgegennimmt,
und hier einen Lambda-Ausdruck öffnen, in dem du tatsächlich den Code
schreibst, um deine Logik weiterzuführen.
Richtig?
Die Logik, die wir hier haben, auf die ich nicht eingehen
werde; mach nichts Kompliziertes.
Das ist eine Art zu sagen: Hey, leg los.
Änderungen speichern und alle sicheren Änderungen.
Die Schritte sind erledigt.
Bitte kommen Sie zurück, dann erledigen wir den Rest des Codes.
Und in dem Zeitraum,
Die Ressourcen unseres Endpunkts werden an die Donnet-Laufzeit zurückgegeben, und sie
kommen wieder, sobald wir weiterfahren.
Jetzt könnten wir es so machen, aber das ist wirklich eine ältere
Art, Aufgaben zu erledigen.
Es gibt eine viel bessere Syntax, die die Schlüsselwörter async und await verwendet.
Also lasse ich das auf diese andere Signatur zurück.
Was wir ausdrücken möchten, ist, dass wir auf diese Ausführung
wirklich warten möchten, richtig?
Wir wollen auf die Ausführung der Aufgabe warten, aber damit das
funktioniert, müssen wir es auch mit dem Async-Schlüsselwort kombinieren.
Also, wenn wir hier auch ganz nach oben gehen.
Zu Beginn unseres Handlers soll hier das Async-Schlüsselwort
endlich eingeführt werden.
Damit sagen wir dem Compiler, dass wir nicht nur einen Aufruf an eine
asynchrone Methode machen wollen, 'changes async', sondern dass der
Endpunkt asynchron laufen soll.
Das bedeutet, dass wir dem Compiler zum falschen Zeitpunkt sagen,
dass hier asynchroner Code läuft.
damit es bereit ist, Ressourcen freizugeben, falls wir
asynchrone Änderungen durchführen müssen, was Zeit kostet.
In dieser Zeit soll die Laufzeit etwas anderes tun, bevor die Kontrolle an
unsere Methode zurückkehrt, damit wir hier die Logik fortführen können.
Als Best Practice suchen Sie auch die asynchrone Version
Ihrer Methoden – wie diese hier.
Änderungen erfolgen asynchron; nutzen Sie async und await, um sie zu kennzeichnen.
die Tatsache, dass du Dinge asynchron ausführst.
Da unser POST-Endpunkt jetzt bereit ist, nehmen wir hier auch die Änderungen
an unserem Get-Endpunkt zur Abfrage nach ID vor, damit er ebenfalls
unseren DB-Kontext verwenden kann und er außerdem asynchron arbeitet.
Also fangen wir damit an, unseren Datenbankkontext hier
als weiteren Parameter des Game Store einzuführen, damit er über
Abhängigkeitsinjektion empfangen wird.
Lassen wir uns hier am Anfang den Async-Modifikator einführen.
Und dann sind wir vollständig bereit, dieses Spiel aus der Datenbank abzurufen.
Also statt dies zu tun, was wir gerade tun würden, folgt
Folgendes: Wir werden 'await' sagen.
Im Kontext, dass Spiele asynchron gefunden werden, und dann geben
wir die Idee des Spiels an.
Der Rest der Logik wird ähnlich sein, oder?
Ist das Spiel neu, bedeutet es, es steht nicht in der Datenbank.
Kehren wir zurück; es wird nicht gefunden.
Wir haben das Spiel gefunden und sind bereit, Antwort zu senden.
Doch bleibt das Problem wie vorher mit dieser Antwort, denn dieses
Objekt ist eine interne Darstellung.
Zu unseren Spielen in der Datenbank wollen wir die interne
Darstellung nicht zurückgeben.
Wir liefern das DTO zurück.
Also lass uns das hier vollständig entfernen und stattdessen ein
neues Spiel zurückbringen.
Details-DTO-Objekt, welches unsere Spiel-ID empfängt.
Dieser Spielname soll eine eindeutige ID erzeugen.
Ziel ist der Preis und das Spiel, sowie das Veröffentlichungsdatum.
Und das sollte gut genug sein, damit unser Get-by-ID-Endpunkt die Spiele
aus der Datenbank abrufen kann.
Also probieren wir das mal aus.
Öffnen wir unser Terminal.
Lass uns einen Probelauf durchführen.
Okay, lass uns das hier schließen.
Gehen wir in unsere Spiel-Datei unter games dot http-Datei.
Und wir haben bereits ein Spiel erstellt, richtig?
Wir haben dieses Spiel schon erstellt, also sollte es in
der Datenbank eine ID 1 geben.
Dann aktualisieren wir hier unseren zweiten Endpunkt mit der Nummer Eins.
Klicke bitte auf Sendeanfrage.
Und wie erwartet können wir dieses Spiel jetzt empfangen.
Wir haben 200, okay?
Und hier unten haben wir den Spielkörper mit der erwarteten Antwort.
Also haben wir jetzt die Möglichkeit, Spiele zu erstellen
und ein Spiel abzurufen.
Aber ID aus DB – nicht nur EF Core, sondern asynchron.
Schauen wir, wie wir den API-Endpunkt aktualisieren, der
alle unsere Spiele abrufen kann.
Der Endpunkt, der diese erste Anfrage beantwortet, ist dort.
Ich öffne das Terminal und stoppe meinen Server.
Wir kehren zu den Spiel-Endpunkten zurück.
Der Endpunkt, den wir ändern wollen, ist dieser hier.
Also wie üblich beginnen wir damit, unseren Kontext für das
Spielgeschäft vorzustellen – hier der Kontext, Abhängigkeitsinjektion.
Dann machen wir unsere Methode asynchron, indem wir hier async verwenden.
Und dann werden wir diesen Ausdruck aktualisieren, ich meine den Handler,
den wir hier definiert haben, damit er nicht mehr Spiele zurückgibt,
sondern stattdessen Folgendes tun wird.
Es wird nun eine Gewichtung des DB-Kontexts vorgenommen.
Spiele,
Und von dort aus werden wir projizieren.
Die Bausteine, die der Kunde erhält.
Wir wollen nicht die Spiele selbst zurückgeben, denn doch wie gesagt wollen
wir Details dazu nicht preisgeben, wie wir Spiele in der DB speichern.
Wir liefern die DTO-Version dieser Objekte zurück; dazu reicht eine SELECT-Abfrage.
Und hier werden wir unser gegenwärtiges Spiel hier in ein völlig neues Spiel
projizieren, das DTO genannt wird.
Jetzt öffnen wir hier unsere Klammer.
Und wir müssen damit beginnen, unsere Werte bereitzustellen, richtig?
Also werden wir unsere game.id, unsere game.name angeben, und im Fall dieses
speziellen DTOs möchten wir bitte String-Version unseres Game-Generates
statt der Generate-ID angeben.
Und das liegt daran, dass wir erwarten, dass das Frontend, das diese Methode
aufruft, sich nicht um konkrete Ideen zum Spiel Generous kümmert, sondern
lediglich eine String-Version genügt.
Wie bekommen wir nun die generierte ID?
Folgendes: Wir können game.generate.name verwenden, um auf die zusammengesetzte
Eigenschaft zuzugreifen.
Beachte, dass generate hier vom Typ Generate ist, und von dieser Eigenschaft
aus können wir den Namen abrufen.
Jetzt sehen wir hier eine Warnung.
Es gibt eine Warnung zur Erkennbarkeit von Degeneriertem.
Das passiert, weil wir Degeneriertes als erkennbar deklarieren; der
Compiler sorgt, dass wir etwas verwenden, das neu sein könnte.
Es ist legitim, Degeneriertes auch mal neu zu verwenden; wie
gesehen, braucht man es nicht immer.
Das erzeugt eine zusammengesetzte Eigenschaft.
Zum Beispiel hier in unserem Endpunkt zum Abruf nach der ID verwenden wir nur
die Generierungs-ID, und wenn wir im POST-Endpunkt hier eine neue Instanz des
Spiels erstellen, verwenden wir erneut nur Generierungs-ID, denn das genügt, um
den Fremdschlüssel zu erfüllen, richtig?
Es gibt jedoch Fälle wie diesen hier, in denen wir auf diese
Eigenschaft zugreifen möchten und anschließend auf die Eigenschaften
innerhalb dieser zusammengesetzten Eigenschaft zugreifen können.
Nun gibt es hier zwei Dinge, die wir erledigen müssen.
Das erste ist, Entity Framework Core zu bitten, das Generierte
auch aus der Datenbank zu laden, sobald die Abfrage gesendet wird.
Zur Eskalation dieses Falls.
Wenn wir das nicht tun, erscheint das Generierte dort als neuer
Wert, und dann stürzt es hier ab.
Um Entitäten in Entity Framework Core zu laden, macht man Folgendes:
Man fügt einfach Include hinzu und gibt dann an, was in der Antwort aus
der Datenbank enthalten sein soll.
In diesem Fall wird es generiert werden.
Also wird EF Core es als Teil der Antwort einschließen, die wir erhalten werden.
Auf diese Weise werden nur die relevanten Beziehungen geladen.
Jetzt versteht der Compiler nicht einfach, dass wir hier durch dieses Include sicher
nen Wert bekommen; er meckert weiter.
Das ist einer jener Fälle, in denen man das Verhalten übernehmen und dem
Compiler sagen kann, dass man sich nicht kümmert, was er davon hält.
Was könnte hier passieren.
Wir wissen, dass das Allgemeine in diesem Fall unbekannt bleiben sollte.
Deshalb können wir den neuen fehlerverzeihenden Operator verwenden
– das Ausrufezeichen, das Sie hier sehen –, wir verwenden ihn, um dem
Compiler mitzuteilen, dass er sich keine Sorgen machen muss, weil wir
wissen, dass das Allgemeine mit einem Wert versehen sein sollte.
Okay, also lass uns jetzt einfach die hier benötigten Merkmale abschließen.
Wir müssen den Preis unseres Spiels und das Release-Datum unseres Spiels angeben.
Jetzt meckert der Compiler hier mit diesen roten Wellenlinien, weil.
Die Rückgabe dieser Abfrage hier ist nicht asynchron.
Also müssen wir diese Antwort in eine echte asynchrone Antwort
verwandeln, etwas, das die Aufgabe wirklich zurückgibt.
Und dazu können wir einfach wirklich ganz direkt nach unserem Select-Aufruf
hier Folgendes tun, damit der Prozess fortgesetzt werden kann.
Bei Align machen wir das so, um Async aufzulisten, indem wir aus
dieser Linkabfrage hier eine wirklich angemessene Antwort nehmen und sie
in eine Aufgabe verwandeln, die eine Liste von Spiel-DTOs ergibt.
Und das sollte funktionieren.
Eine gute Praxis hier ist, EF Core zu bitten, die zurückkehrenden
Ergebnisse nicht zu verfolgen.
Standardmäßig will es alle dieser Entitäten verfolgen, falls du Änderungen
an ihnen vornehmen und sie in die Datenbank zurückspeichern willst.
Wie Sie sehen, besteht alles, was wir tun, darin, einfach mit der Datenbank
zu sprechen und die Werte zu liefern.
Es gibt hier keine weitere Logik.
Sehr einfach.
Um hier Leistung zu erhöhen und zu fragen, ob Core diese Entitäten
nicht verfolgen soll, müssen Sie einfach sagen: Kein Tracking.
Und jetzt wird der EF Core-Tracker für diese Antwort abgeschaltet,
und die Abfrage wird im Wesentlichen schneller sein.
Bevor wir das hier testen, noch eine Sache: Wir sollten unseren Game-DTO
hier umbenennen, denn jetzt haben wir Spiel-Details, C#, TO und dieses DTO.
Dann kläre ich, worum es bei dem DTO geht.
Also nehmen wir das Contra-Shift-Team, um unseren Datei-Explorer zu öffnen.
Lass uns ins Spiel-DTO gehen.
Und was ich gerne tun würde, ist einfach, das Game-DTO in ein
Game-Zusammenfassungs-DTO umzubenennen.
Das wird der neue Name sein: Game-Zusammenfassungs-DTO für die Datei.
Und für den eigentlichen Datensatztyp werde ich F zwei
verwenden und hier Game einsetzen.
Also Eingabe.
Okay, zurück zu den Gains-Endpunkten.
Wir sollten hier und auch an anderer Stelle in dieser Datei erkennen können,
dass der neue Name verwendet wird.
Jetzt probieren wir das aus.
Also öffnen wir jetzt das R-Terminal, Strg-J.
Ich starte jetzt meinen Server.
Ich.
Okay, lass uns das hier schließen.
Wir gehen zurück zu unserer Games-Datei, damit unsere Antwort interessanter
wird, und wir sollten mindestens ein weiteres Spiel hinzufügen, damit
wir mehrere sehen können, ja, bitte?
Also habe ich eine weitere Nutzlast für unsere POST-Methode vorbereitet,
die ich hier einfügen werde.
Also ist das jetzt drei Kämpfer, zwei davon mit Erzeuge Eins, was
unsere Kampf-Generierung sein sollte.
Hier der Preis und das Datum.
Also, lass uns jetzt die Anfrage absenden.
Okay, also wurde das Spiel erstellt, richtig?
Es wurde erfolgreich erstellt.
Hier sehen wir, dass die ID-Nummer zwei und Januar eins zugewiesen wurden.
Also können wir jetzt unseren Endpunkt Alle Spiele abrufen
testen, der erste in unserer Datei.
Lass uns jetzt auf Anfrage senden klicken.
und wir sehen, dass dort eine erfolgreiche Antwort eingegangen ist.
200. Okay.
Und wir sehen die Antwort der Methode, die jetzt beide unsere
Spiele zurückbringt, richtig?
Also hier haben wir Super Mario Overdose Wonder und unser Three Fighter 2-Spiel.
Beachten Sie, dass selbst dann, wenn die Generatoren in der Spieletabelle als IDs
gespeichert sind, wir hier die eigentliche Zeichenfolge des Generators extrahieren
konnten – sowohl für Super Mario Bros hier als auch für Three Fighter Two.
Jetzt fahren wir mit unserem folgenden Endpunkt fort, der ganz
sicher der PUT-Endpunkt sein wird.
Also
Lass uns unseren Server stoppen.
Lass uns das hier schließen.
Lass uns doch zu den Spiel-Endpunkten zurückgehen, und nach unserem suchen.
Karte, schieb den Anruf hierhin.
Wie üblich.
Lass uns unseren Spieleladen-Kontext vorstellen.
Dort drüben ist unser DB-Kontext.
Vielleicht schicke ich die Dinge zur nächsten Folie,
damit wir sie besser sehen.
Die Bezeichnung 'Signatory' ist doch etwas lang.
Danach werden wir die Methode asynchron gestalten, indem wir
hier, wie es üblicherweise der Fall ist, das Async-Schlüsselwort
einführen, in der Praxis.
Bezüglich der Umsetzung werden wir das nicht mehr tun, und
stattdessen führen wir Folgendes aus.
Wir werden es mit 'we bar' erledigen.
Das vorhandene Spiel wird zu einem Gewicht im Gesamtkontext werden,
der Spiele betrifft, die Async verwenden, in dieser Hinsicht.
Und wir geben unsere ID.
So finden wir das Spiel.
Aber natürlich kann es schon sein, dass wir das Spiel nicht finden.
Dann wäre das vorhandene Spiel neu.
Und in dem Fall müssen wir tun, was wir hier schon versucht haben.
Was wir in diesem Fall tun.
Es dient lediglich dazu, zu prüfen, ob das vorhandene Spiel wirklich neu ist.
Wir liefern weiter Resultate, die nicht gefunden sind.
Dann geht's weiter.
Wir aktualisieren das Spiel, das wir gefunden haben.
Es muss nun mit den neuen Eigenschaften der eingehenden Daten aktualisiert werden.
Also tun wir das.
Der bereits vorhandene Spielname lautet derzeit aktuell Updated Game.
Nenne den Namen bitte.
Die vorhandene Spiel-ID wird derzeit sehr zügig aktualisiert.
Bitte tu es jetzt sofort.
Idealerweise generieren wir eine ID, aber wie man sieht, steht die
generierte ID im aktualisierten KDTO nicht zur Verfügung, ähnlich dem, was
mit unserem POST-Endpunkt passiert ist.
Also lasse ich hier einfach F12 drücken, um zu unserem DTO zu
gelangen, und dies ist der Moment, dieselbe Änderung vorzunehmen,
die wir mit unserem gemacht haben.
Erstelle hier ein Game-DTO mit der Generate-Funktion.
Vielleicht schauen wir kurz auf unser Create-DTO, damit wir dieselbe Eigenschaft
mit gleichen Beschränkungen übernehmen, die wir bisher festgelegt haben.
Okay.
Das beende ich hier.
Ich kehre zurück, um das Game-DTO zu updaten, und ich schalte es
auf ID-Generierung mit einem Bereich von eins bis fünfzig um.
Damit kehren wir zu den Endpunkten des Gewinns zurück und nutzen
unsere neue ID-Eigenschaft.
Nun lasst uns dies abschließen, indem wir das bestehende Spiel bearbeiten.
Der Preis wurde aktualisiert, das Spiel, dieser Preis, und schließlich die
Veröffentlichung des bestehenden Spiels.
Das Datum wurde aktualisiert.
Bitte geben Sie das Veröffentlichungsdatum des Spiels an.
Und das Letzte, was wir hier tun müssen, ist, Core zu bitten, diese
Updates in die Datenbank zu senden.
Dafür bleibt uns nichts anderes übrig, als geduldig abzuwarten, dass der
Kontext sichere Änderungen ermöglicht.
Noch einmal, ich.
Und das ist alles, was wir tun.
Um unseren Endpunkt für Updates in die Datenbank vorzubereiten.
Jetzt testen wir es.
Dann starten wir Server neu.
Ich starte ihn hier.
Okay, lass uns dieses Terminal schließen.
Kehren wir zu den Gangs bei HGTP zurück.
Und dann ist das Vorgehen, das wir dieses Mal nutzen, hier: unsere PUT-Anfrage.
Bevor wir Änderungen vornehmen, erinnern wir uns kurz daran, wofür wir unser
strenges Fighter-2-Spiel erstellen, nämlich den Inhalt unserer POST-Anfrage.
Also kopiere ich hier wirklich unseren POST-Body hinein.
Bitte nutze ihn als Grundlage für unsere PUT-Anfrage.
Den hier werde ich jetzt einfügen.
Stellen wir sicher, dass wir die ID des Spiels aktualisieren, richtig?
Also, das ist wirklich nicht Spiel Eins; dieses hier wird ganz sicher
Spiel Zwei sein, oder nicht wahr?
Das ist ganz klar Three Fighter Two.
Und na ja, beim eigentlichen Update machen wir es so, dass es Strikt
Fighter Zwei Turbo sein wird, und der Preis diesmal wird einfach
deutlich teurer sein, oder nicht?
1999.
Nun lass uns bitte eine Anfrage senden.
Also sende bitte die Anfrage.
Wir haben den Status 204 No Content sofort erhalten, was
bedeutet, dass es gelungen ist.
Alles gut, wirklich.
Und ähm, nun bestätigen wir einfach, dass das Update erfolgt ist, indem wir
zum Get-By-ID-Endpunkt zurückkehren.
Dieses hier.
Lassen wir Nummer zwei verwenden.
Klicken wir darauf und senden die Anfrage.
Und wie erwartet erhalten wir ganz sicher den Namen 'C# Fighter
zwei Turbo' und den Preis.
War das Update.
Nun wechseln wir zum letzten Endpunkt, dem Lösch-Endpunkt.
Also schließen wir das bitte.
Lass mich den Server stoppen und zu den Spiele-Endpunkten wechseln.
Wir schauen uns jetzt hier doch unseren Lösch-Endpunkt an.
Und wie üblich können wir damit beginnen, unseren Spielstore gründlich
und auch detailliert vorzustellen.
Kontext-Datenbank-Kontext.
Wir machen die Methode asynchron.
Und um das Spiel dauerhaft aus der Datenbank zu entfernen, gibt es einige
Möglichkeiten, doch meines Erachtens ist die effizienteste davon die
nachfolgend beschriebene Vorgehensweise.
Wir werden in diesem Zusammenhang den DbContext für Games verwenden.
Anschließend bedienen wir uns der WHERE-Klausel, um die
passenden Datensätze zu filtern.
Wir sagen dann eindeutig, dass game.id gleich id ist.
Also filtert das sämtliche Spiele, bis wir ein bestimmtes Spiel
finden, das wir löschen möchten.
Von dort aus können wir hier eben die wirklich asynchrone
Delete-Methode ausführen.
Welche ist diejenige, die noch genau diese Löschung aus der Datenbank auslöst?
Dieses Muster hier, das ich nutze, ist das, was man als
Massenlöschung bezeichnet.
So löscht es alle Spiele, die diesem hier angegebenen Filter entsprechen.
Nicht der einzige Weg, doch er ist wirklich sehr effizient, weil er nur
einen DB-Zugriff braucht, um die Löschung durchzuführen, falls er das Spiel findet.
Nur damit Sie es verstehen: In dem Fall gibt es keinen
sicheren Änderungsaufruf, oder?
Also keinen sicheren Änderungsaufruf, weil alles sofort geschieht, oder?
Nur ein Aufruf an eine DB, der die Löschung ausführt; dann ist das Spiel
verschwunden, falls es jemals gab.
Okay, also probieren wir das mal aus, indem wir unseren
Server noch einmal starten.
Okay, ich schließe das hier.
Geh zurück zu games dot http und teste diese, da ich keines meiner
Spiele wirklich verlieren möchte.
Ich füge einfach ein Testspiel hinzu.
Nennen wir es einfach Testspiel.
Okay?
Die restlichen Details spielen keine Rolle.
Ich klicke auf Anfragen zum Posten.
Okay, das Spiel wurde erstellt, und es ist Spiel Nummer Drei.
Es handelt sich um Spiel Nummer Drei.
Wir können dort den Standort von Spiel Nummer Drei sehen.
Bestätigen wir, dass das Spiel in der Datenbank vorhanden ist, indem
wir unsere zweite Anfrage verwenden.
Finden wir dieses Spiel jetzt.
Ja, es ist dort.
Also löschen wir es jetzt, indem wir zum letzten Endpunkt hier
gehen, unseren Lösch-Endpunkt.
Wir machen das ja für Spiel Nummer drei.
Lass uns auf Senden klicken.
Wir bekommen eine 204 No Content-Antwort, was bedeutet, dass dies erfolgreich
war; das Spiel wurde gelöscht.
Und das bestätigen wir, indem wir erneut den ID-Abruf für Namen Nummer
drei aufrufen, damit wir sicher gehen.
Lass uns erneut auf Senden klicken.
Natürlich bekommen wir 404 – nicht gefunden – das
Spiel ist jetzt verschwunden.
Damit ist die Implementierung unserer Spiele-API abgeschlossen.
Äh, aber bevor wir zum Nächsten übergehen, schauen wir uns einfach
unsere Spiele-Endpunkte an.
Und denkt daran, auch den Anfang dieser Datei zu bereinigen, denn dieses
Spiel-Array ist jetzt völlig nutzlos.
Also können wir jetzt einfach alles auswählen, okay.
Und lösche es.
Behalte nur die Endpunkt-Definitionen, die sich auf die Datenbank beziehen.
Unsere Spiel-API ist vollständig.
An diesem Punkt haben wir alle Endpunkte unserer Spiele-API abgeschlossen.
Wir brauchen jedoch einen weiteren Endpunkt, nicht für Spiele, sondern
für Spielgeneratoren, weil das Frontend eine Möglichkeit braucht, diese in
der Benutzeroberfläche anzuzeigen.
Die Liste aller verfügbaren Spielgeneratoren lässt dem Benutzer
die Auswahl eines davon zu.
Im Fenster zur Spieleerstellung.
Nutze alles, was wir in diesem Kurs gelernt haben.
Um rasch einen neuen Endpunkt zu bauen, der alle Datensätze abrufen kann.
Lasst uns zuerst den Lösungs-Explorer öffnen.
Lasst uns das hier bitte zuklappen.
Gehen wir hier in unser Projekt hinein.
Gehen wir in DTS, klicken mit der rechten Maustaste und fügen eine neue
Datei hinzu, die vom Typ 'Record' ist, und benennen wir diese 're DTO'.
Öffnen wir sie.
Wir entfernen hier den Klassenmodifikator, und dies wird ein sehr einfaches
Datentransferobjekt sein, das nur eine ID für den eindeutigen
Bezeichner der Entität hat und dann noch einen Namen als Zeichenkette.
Dies ist das DTO, das für die Antwort unseres neuen Endpunkts
verwendet wird, der alle dieser Spieleadressen abrufen wird.
Jetzt setzen wir den eigentlichen Endpunkt schrittweise um.
Gehen wir nun wieder in unseren Solution Explorer, und navigieren
diesmal in den Endpunkte-Ordner.
Lasst uns bitte mit der rechten Maustaste auf Neue Datei klicken.
Das wird eine Klasse sein.
Nennen wir sie Jes Endpoints.
Lasst uns hier mal öffnen.
Zuklappen.
Entfernen wir den überflüssigen Leerraum.
Diese Klasse muss statisch sein, weil sie statische Methoden hat,
die als Erweiterungsmethoden dienen.
Wir deklarieren diese Methode.
Sie wird öffentlich statisch sein.
Nichts.
Eine großzügige, breit angelegte Karte und mehrere Punkte, die
dazu beitragen werden, unsere Web-Allokations-App deutlich zu erweitern.
Wir werden unsere Routengruppe definieren, deshalb setzen
wir Bar-Gruppe als App fest.
Das ist unsere Karten-Gruppe.
Der Wurzelpfad dieser Gruppe ist einfach großzügig; hier
gibt es nur einen Endpunkt.
Eine Gruppe zu haben und alle Endpunkte dieser Gruppe anzuhängen,
folgt auch dieser Konvention.
Und tatsächlich ist der Endpunkt, den wir hier äußerst präzise definieren
möchten, ein GET-Endpunkt, der auf einen Aufruf an generous reagieren wird.
Dazu setzen wir die Gruppe group.app ein.
Wir werden wirklich in die Hood-Route hineinwechseln, direkt unter res.
Dann legen wir hier unseren asynchronen Handler; er wird asynchron.
Es empfängt unseren Game-Store-Kontext.
D-Kontext.
Stellen Sie sicher, dass wir C#-Steuerung verwenden, damit wir die
King Store API-Daten verwenden können.
Und dann verweist dies auf die nachfolgende Implementierung.
Vielleicht.
Wir schließen es vorerst.
Hier möchten wir asynchron auf den DB-Kontext zugreifen.
Großzügig gedacht, und wir werden das entsprechend projektieren.
Also werden wir auswählen, neu generieren und ein DTO erzeugen, was
wir in dieser Aufgabe zu tun haben.
Um dieses API bzw.
DTOs zu verwenden, setzen wir in C# einen Controller ein, um es sicher
zu speichern und später abzulegen.
Und für das generierte DTO geben wir D zurück, erzeugen eine eindeutig
identifizierbare ID, und Gen bleibt dabei.
Name
Wir werden EF Core bitten, diese Daten nicht zu verfolgen, weil wir sie in
keiner Hinsicht verändern möchten.
Auch keinerlei Art der Nachverfolgung.
Und schließlich wandeln wir das in eine Liste um, synchron,
was unseren asynchronen Aufruf letztlich vollständig abschließt.
Also ja, das ist so ziemlich alles.
Das ist unsere Definition von unserem Endpunkt dort.
Und natürlich müssen wir jetzt auch wieder in unser File-Explorer-Programm Cs gehen.
Und vielleicht hier, nach unserem Map-Games-Endpunkt-Aufruf,
können wir einen Aufruf an App Map Generous Endpoints machen.
Und Na ja, das ist so ziemlich alles.
Unser neuer Endpunkt ist ja bereit und wir können ihn gleich ausprobieren.
Drück hier Strg-J, damit unser Terminal startet.
Gehen wir in die Game-Store-API, machen es, tun es, führen es aus.
Okay, es läuft entgegen der Verschiebung E. Gehen wir in Gains
HT TP; das muss verloren gehen.
Und was ich tun werde: Lass uns einfach bis zum Ende gehen, um hier noch
eine weitere Anforderung einzuführen.
Also drei Rautezeichen; der Host-Import wird derselbe sein.
Also kopiere ich den Host und das Portal aus dem Löschaufruf genau dort hinein.
Hier setzen wir einfach 'großzügig' hinein.
Klicken wir jetzt auf 'Anfrage absenden'.
Und auf der rechten Seite sehen wir, dass wir den erwarteten
Status 200 erhalten haben.
Okay.
Es war ein Erfolg.
Und hier sehen wir die ganze Liste aller Spiele, die wir in
der Datenbank gespeichert haben.
Unser Backend-API ist vollständig und einsatzbereit für die Integration
in die Frontend-Anwendung.
Auch wenn dieser Kurs ASP.NET Core behandelt, sehe ich, wie die API,
die wir im Kursverlauf erstellen, eine wirklich echte hochmoderne
Benutzererfahrung ermöglicht.
Dafür habe ich eine kleine React-App vorbereitet, die
mit unserer NET-API spricht.
Nun zeige ich dir heute in diesem Lehrgang, wie du diese Anwendung hier
so konfigurierst, dass sie mit der von uns erstellten API kommuniziert.
Wie Sie sehen können, habe ich hier einen neuen Leiter,
GameStore, der React heißt, jetzt.
Dies ist die React-App, und wenn wir hier öffnen, werden wir eine Menge Dateien
finden, aber die Hauptdatei, die wir uns schnell ansehen möchten, ist vite.config.
Dies ist die Datei, in der wir die Konfig festlegen.
Für die lokale Ausführung der Anwendung in diesem Fall verwenden
wir den Bit-Server hier wirklich.
Die Art und Weise, wie die Dinge eingerichtet sind.
Jedes Mal, wenn irgendeine der Komponenten dieser Anwendung mit
dem Backend kommunizieren muss, wird sie den Slash-API-Standort aufrufen,
der über diese Proxy-Konfiguration auf unsere Backend-URL verweist.
Nun, wo befindet sich unsere Backend-URL?
Nun, merken wir uns das schnell.
Wenn wir Strg+Umschalt+E öffnen, unseren Explorer, gehen wir in unseren Game Store,
API-Eigenschaften, Launch-Serie und Jason.
Und denk daran, dass wir hier unser HTTP-Profil haben, in dem
wir die Anwendungs-URL für die lokale Entwicklung festlegen.
Also werde ich einfach diese Anwendungs-URL kopieren, diese URL
kopieren, Strg-A, Umschalt-E drücken.
Lassen Sie uns dann in diese Config.ts zurückgehen, dort
diesen Speicherort einfügen.
Und damit sind wir bereit, die vollständige Full-Stack-Anwendung
in Aktion zu sehen.
Also
Ich drücke Strg-J, um Terminal zu öffnen.
Vielleicht vergrößere ich das Terminal.
Ich starte zuerst unsere Server-App.
Also startet unser Spiel per API.
Ich führe net run aus.
Und dann benutze ich hier diesen Plus-Button, um ein weiteres Terminal
zu öffnen, das von ihnen verwendet wird, um die React-Anwendung zu starten.
Also gehe ich jetzt in Game Store, React,
Und da dieses hier auf Node.js basiert, muss ich daher NPM Round
Dev zudem noch jetzt durchführen.
Eine Anwendung ist bereits gestartet.
Wir können hier die lokale URL der App sehen, die ich auf localhost:5173
kopieren werde, und hier in meinem Browser füge ich die Zuordnung ein.
Dort wurde es eingegeben.
Und hier sind wir in unserer Anwendung.
Wie Sie sehen können, wurde die Startseite unmittelbar geladen.
Die beiden Spiele, die wir zuvor erstellt hatten.
über REST-Client in VS Code.
Um nun zu bestätigen, dass diese Anwendung wirklich mit unserem
Backend spricht, können wir hier ganz einfach F zwölf drücken, um die
Browser-Entwicklertools zu laden.
Und wenn wir hier in die Netzwerk-App gehen, hier ist sie.
Wir öffnen jetzt diesen Teil, in dem wir ja alle Rufe sehen, die
das Frontend an das Backend sendet.
Ich aktualisiere es hier wirklich einfach jetzt.
Ich sehe hier rechts mehrere Rufe, die alle Aktionen und Dinge zeigen, die
das Frontend beim Laden durchführt.
Nun ist hier viel los, also werde ich einfach filtern.
Ja, dieser Button, ich filter nur die Aufrufe, die nach außen gehen
und in unser Backend gelangen.
Dafür klicke ich hier bei fetch/xhr.
Ja, das wird dann nur die Fetch-Aufrufe offenlegen, bei denen Fetch die API
in JS ist, die du verwenden kannst, um mit externem Dienst zu kommunizieren.
Also hier sehen wir tatsächlich, dass wir mehrere Fetch-Aufrufe
haben, die alle hier sichtbar sind.
Klicken wir bitte auch auf einen davon.
Wenn wir das weiter erweitern, sehen wir hier klar unsere Anfrage, die URL, die
in den Pfad /api/games/location führt.
Nun, wie kommt das in unsere Backend-API hinein?
Denn die API existiert nicht in 51, 73; so funktionieren diese Dinge jedoch.
Wie ich schon sagte, kehrt es zu VS Code zurück.
Wenn wir uns unsere config.ts rechts ansehen, lass mich das mal
zusammenklappen; das Frontend ruft die Slash-API auf, und dann wird die
Slash-API auf unseren eigentlichen Speicherort übersetzt, wobei der
API-Teil der Slash-API entfernt wird, und dann sind wir nur noch.
Ich werde den Rest des Pfades aufrufen, und der Rest dieses Pfades
wird nur Slash-Spiele sein, was
Endpunkt der Netz-API.
Jetzt gehen wir in unsere UI und klicken einfach auf Neues Spiel,
um unser Spiel zu erstellen.
Und hier: Ich klappe das jetzt kurz zusammen, denn unser
Endpunkt wurde aufgerufen.
Hier sehen Sie, dass ein Aufruf an den großzügigen Endpunkt erfolgt.
Wir klicken drauf.
Wir sehen den Weg, in die großzügige API zu gelangen,
die wir gerade erstellt haben.
Da ist es.
Lasst uns gemeinsam ein ganz neues Spiel entwickeln.
Wir sagen einfach, dass dies unser Astro-Vote-Spiel sein wird.
Es handelt sich um ein Plattformspiel, also um ein Spiel mit
Jump'n'Run-Elementen, das Geschicklichkeit und ein präzises Timing erfordert.
Hier ist der Preis, und für den Tag legen wir fest, dass 9 6 20 24 gelten.
Ähm, schließt es dann bitte ab.
Klickt anschließend auf Speichern, damit eure Änderungen gespeichert werden.
Und hier siehst du: Unser Aufruf zu Games liefert eine 201.
Dies ist der Aufruf, das Spiel zu erstellen.
Wir klicken darauf.
Wir sehen, dass es sich um eine POST-Anfrage war und wir tatsächlich
den Status 201 erhielten, ähnlich wie im REST-Client von VS Code.
Wir könnten es auch aktualisieren; hier drei Fighter zwei.
Das wird jetzt drei Fighter Zwei, nennen wir es mal 'Super'.
Der Preis wird, sagen wir, vermutlich nur sieben Komma
neun neun betragen, sehr billig.
Klicken Sie auf Speichern.
Und das Spiel ist aktualisiert, wie man hier sieht.
Schließlich können wir fortfahren und
Teste die Löschung eines Spiels.
Sagen wir also, dass wir das Super Mario Bros. Wonder-Spiel nicht mehr möchten.
Wir können hier auf den Lösch-Button klicken, dann auf Löschen, und
das Spiel ist wirklich weg.
Also, da hast du es.
Äh, eine wirklich moderne Full-Stack-Anwendung, jetzt
betrieben von der your.net-API.
und Reaktionstext.
Also, wohin gehen wir von hier genau?
Zuerst die Code-Struktur, das ist die Grundlage unseres Codes.
Derzeit ist alles an einem Ort – das wird in großen Anwendungen zum Albtraum.
Man kann eine vertikal ausgerichtete Architektur verwenden, damit
Funktionen sauber bleiben.
Dann Authentifizierung und Autorisierung, speziell, wie Sie Ihre APIs mit
Microsoft Intra ID absichern.
Der branchenweite Standard, der heute in den meisten Großunternehmen gilt.
Danach sollst du lernen, wie man deine API-Endpunkte testet, so wie
echte Anfragen sie treffen, auch bekannt als Integrationstests.
Dann möchtest du alles, was du gebaut hast, containerisieren und
es in die Azure-Cloud verschicken.
Hier wird dein Code jetzt wirklich zu einem echten Produkt.
Und wenn du bereit bist, setze auf Full-Stack mit einem modernen
React-Frontend, um eine echte, praxisnahe Anwendung von Anfang bis Ende zu erleben.
Meistere diese Skills und entwickle produktionsbereite Backends, Schritt für
Schritt in meinem .NET Backend-Bootcamp.
Details findest du unter dotnetacademy.io/bootcamp.
Danke fürs Zuschauen – wir sehen uns im nächsten Video.
Full transcript without timestamps
Heute lernst du, wie du eine vollständige REST-API mit ASP.NET Core und C# schrittweise erstellst. Wir starten ganz von vorn, Endpunkte erstellen, eine Datenbank über Entity Framework Core verbinden und Validierungen hinzufügen. Du lernst Dependency Injection, asynchrone Programmierung und auch, wie man eine saubere Code-Struktur bewahrt. Am Ende verbindest du deine API mit einem modernen React-Frontend und siehst, wie alles funktioniert, ja. Legen wir los. Ihr Unternehmen baut einen Videospiel-Shop auf. Das Frontend-Team hat das Spielkatalog-UI bereits erstellt. Ihre Aufgabe besteht darin, das Backend zu entwickeln, das es antreibt. Alle Spieldaten werden in einer Datenbank gespeichert, und Sie stellen die Daten über eine REST-API mit Endpunkten zum Erstellen, Lesen, Aktualisieren und Löschen von Spielen bereit. Dieser Kurs zeigt Ihnen, wie man dieses Backend von Anfang bis Ende mit ASP.NET Core und C# erstellt. Sie beginnen damit, zu lernen, wie man Ihre erste ASP.NET Core-Anwendung von Grund auf erstellt, ausführt und debuggt. Danach gehen wir auf die Kernkonzepte hinter REST-APIs ein und zeigen, wie man die traditionellen CRUD-Endpunkte in einer ASP.NET Core API schnell implementiert. Beim Implementieren Ihrer REST-API prüfen Sie DTOs genau, um den Vertrag zwischen Ihrer API und dem Frontend festzulegen. Dann wirst du sehen, wie man Erweiterungsmethoden und Routengruppen nutzt, um API-Endpunkte gut zu ordnen. Du wirst auch Zeit verbringen, ungültige Eingaben testen, um zu lernen, wie sie von deiner API behandelt werden. Als Nächstes führen Sie die Datenbankunterstützung über das beliebte Entity Framework Core ein, das in der .NET-Plattform enthalten ist. Dies bietet zudem eine Chance, das ASP.NET Core-Konfigurationssystem wirklich kennenzulernen, das Hardcodierung vermeidet und Konfigurationsdetails in Ihrem C#-Code erleichtert. Als Nächstes erläutern Sie Designmuster der Abhängigkeitsinjektion und wie die Laufzeit von Diensten in ASP.NET Core funktioniert. Hier lernst du, wie du Entitäten auf DTS abbildest, damit der Datenvertrag mit Frontend flexibel bleibt und das Datenmodell erhalten bleibt. Sie schließen Ihre Risik-API-Implementierung ab, indem Sie das asynchrone Programmiermodell einführen, damit Ihre Anwendung die Ressourcen des Webservers möglichst effizient nutzt. Und zum Abschluss zeige ich Ihnen, wie Ihre REST-API gut in das Frontend integriert wird, um eine moderne Benutzererfahrung zu ermöglichen. Um mitzukommen, brauchen Sie auch zwei Dinge: das .NET SDK, das es Ihnen ermöglicht, .NET-Anwendungen zu erstellen und auszuführen, und Visual Studio Code. Den Editor verwenden wir im Kurs. Wir fügen auch VS Code-Erweiterungen hinzu, die ich dir im Kurs zeige. SDK und VS Code installiert. Mal sehen, wie man Ihre Entwicklungsumgebung einstellt. Lassen Sie uns sehen, wie man Visual Studio Code für die .NET-Entwicklung einrichtet. Als Erstes sollten wir prüfen, ob .NET ordnungsgemäß auf dem Rechner installiert ist; dazu können wir die .NET-Kommandozeile oder CLI verwenden. Zu diesem Zweck öffnen wir das Terminal von VS Code, das wir über die Menüleiste finden können. Genau hier jetzt. Öffnen wir das Terminal und dann ein neues Terminal. Und hier ein kurzer Tipp. Man kann die Strg-Tilde-Verknüpfung verwenden, um das Terminal sehr schnell zu öffnen und wieder zu schließen. Oder unter Windows geht das auch. Du kannst Strg-J verwenden, das hat denselben Effekt. Jetzt klicke ich hierher, um dieses Terminal für einen kurzen Moment zu vergrößern, damit es den gesamten Bildschirm ausfüllt. Und jetzt geben wir einfach net ein, das uns Zugriff auf das .NET C# ermöglicht, und danach tippen wir --version ein. Und das, wie man sehen kann, zeigt uns schließlich die aktuelle Version des Install.NET SDK an. Eine weitere Sache hier: Falls ich das schnell erledige, tippen Sie Do net info, das uns mehr Informationen über die installierte Version von net S C# K liefert. Wie Sie sehen, enthält net S C# K alle Details. Außerdem erhalten Sie Details zu Windows und viele weitere Informationen darüber, was Sie in Bezug auf .NET installiert haben. Da wir alle Informationen ohne Probleme abrufen konnten, ist unsere Installation korrekt. Jetzt klicken wir hier auf dieses Papierkorb-Symbol, um das Terminal zu beenden. Und gehen wir zum nächsten Schritt über, der die Installation eines Add-ons ist, das unsere C#-Diagrammentwicklungserfahrung in PS Code sehr deutlich verbessern wird. Dafür öffnen wir die Erweiterungsansicht auf der linken Seite. Und hier möchten wir Folgendes jetzt tun: Wir suchen nach einer Erweiterung namens C# Sharp Dev Kit, die hier Ihre erste Wahl sein sollte. Dies ist ein C# Sharp Dev Kit. und dies wird die Haupt-Erweiterung sein, die entworfen wurde. Um dir beim Erstellen von C#- und .NET-Anwendungen in VS Code zu helfen. Lasst uns hier auf das Widget klicken. Und nachdem es fertig ist, sollten wir schnell sein. Ja, erledigt. Was ich zeigen möchte: Diese Erweiterung installiert nicht nur eine, sondern mehrere. Also klickt hier auf dieses Widget, um unsere Box dort drüben zu leeren. Lass mich das mal ganz kurz wirklich zusammenfassen. Und das, was du hier siehst, wenn es sich nun zusammenfaltet, ist, dass wir jetzt einige installierte Erweiterungen haben. Dazu gehört hier die C#-Erweiterung, die die grundlegende Sprachunterstützung für C# bietet, damit du die korrekte Syntaxerkennung deines C#-Codes hast. Und diese intelligente Unterstützung. Dann bekommst du C#, Erweiterung, die wir installiert haben, um VS Code zu erweitern, wie den Solution Explorer, damit du Projekte und Abhängigkeiten verwalten kannst, und mit dieser Erweiterung kannst du Unit-Tests auch ausführen, falls nötig. Und oben sehen wir, dass dort das NET-Installationswerkzeug vorhanden ist, das tatsächlich eine Erweiterung ist. Es wird von anderen Plugins wie C#-Erweiterung und C#-Kit genutzt, um eine Version von .NET SDK oder Laufzeit zu installieren, falls diese Plugins sie benötigen. Wir nutzen im Kurs noch ein paar Erweiterungen, aber vorerst ist das gut zum Start. Brechen wir das jetzt. Und jetzt sind wir bereit, unser .NET-Projekt zu erstellen. Wie man das macht? Nun, es gibt einige Wege, es zu tun. Der erste Weg besteht darin, erneut das .NET-CLI zu verwenden. Dafür öffne ich erneut mein Terminal. Hier ist mein Terminal. Und was du tun kannst, ist net new list einzugeben und Enter zu drücken. Und was das bewirkt, ist dir eine vollständige Liste aller Vorlagen zu zeigen. Für verschiedene Arten von Anwendungen, die mit deinem .NET bzw. C# beginnen können. Nun, wenn du doch mal ganz zum Anfang gehst, Wir bemerken, dass der dotnet-CLI erste Informationen darüber liefert, was Sie installiert haben. Telemetrie und Details werden nicht behandelt, das lasse ich. Das zeigt nur beim ersten Mal, die eigentliche Liste ist hier. Das ist die Liste deiner Vorlagen, mit der du verschiedene Apps erstellen kannst. Also, falls Sie eine brandneue und leere ASP.NET Core-App wirklich erstellen möchten, könnten Sie das hier verfügbare Web-Template verwenden. Von hier aus könnten Sie Folgendes tun: Lassen Sie mich das kurz klären. Sie könnten dotnet new web verwenden und ihm einen Namen geben. Zum Beispiel installieren Sie diese API, und damit wird Ihre Web-App erstellt. Doch das ist nur ein Weg, es zu tun. Und seit wir das C#-Chart-Kit geklaut haben. Wir haben einen besseren Weg. Also beende ich Terminal erneut. Und diesmal gehen wir in unsere VS Code-Befehls-Palette, die wir erreichen, indem wir erneut in unser Menü gehen. Lass uns die Befehls-Palette öffnen. Und nochmals ein kurzer Hinweis: Verwende die folgende Tastenkombination, um schnell dorthin zu gelangen. Unter Windows kannst du Strg+Shift+P drücken, und damit öffnet sich diese Palette sehr schnell. Die Farbpalette ist wirklich sehr nützlich. Es ist gut, schnell darauf zuzugreifen. Jetzt kannst du einfach type.net eingeben, und das zeigt dir alle Befehle, die derzeit mit dem .NET SDK verbunden sind, wie du sehen kannst, ohne weitere Schritte. Der erste Befehl ist der .NET New Project-Befehl, mit dem wir unser Projekt erstellen und damit direkt starten. Lass uns darauf klicken. Nochmals erhalten Sie die vollständige Liste aller installierten .NET-Vorlagen, die Sie verwenden können, um Ihre Apps in Visual Studio Code zu erstellen. Nun zu Zwecken des Kurses. Eine der Vorlagen, die Sie verwenden könnten, um Ihr Projekt zu erstellen, wäre die ASP.NET Core Web-API-Vorlage, die hier verfügbar ist. Und diese hier wäre ideal, wenn Sie bereits etwas Erfahrung mit der Entwicklung von Web-APIs in .NET haben. Allerdings empfehle ich diese hier nicht. Wenn Sie ganz neu in solchen Anwendungen sind, wird das eine Menge Dateien und Konfigurationen mit sich bringen. Das könnte gleich verwirrend sein. Stattdessen empfehle ich dir, wirklich mit der A-Vnet-Core-leeren Vorlage zu beginnen. die dir eine saubere Grundlage mit wenigen Dateien verschafft, damit du loslegen kannst. Dort kannst du starten, Code und Dateien hinzuzufügen, während du genau verstehst, wofür jedes Teil gedacht ist, während du sie integrierst. Lass uns fortfahren und auf ASP.NET Core Empty klicken. Lass mich in meinen Projektordner wechseln. Und hier möchten wir den Ordner erstellen, der künftig als Arbeitsbereich für unsere Arbeit in Business Studio Code dienen wird. Und da wir an einer Spiele-Shop-Anwendung arbeiten, erstelle ich ganz einfach einen brandneuen Ordner, den wir Store nennen werden. Okay. Ich geh in Ordner. Dann wähle ich den Ordner aus. Dann trag ich den Namen unserer App ein. Nennen wir es. Game Store API, denn es wird die NET-Risk-API sein. Lass uns Endtiefe erreichen. Und hier bitten wir um das Format unserer Lösung. Reichen Sie die Lösung in .NET ein. Das ist es, was VS Code sagen wird, und zwar welche Projekte du bearbeiten wirst und wie sie zusammenhängen. Dieses SLN ist echt die alte Version und nicht praktisch. SLNX ist die neuere, modernere Version. Also empfehle ich dir, l und X zu wählen, wo möglich. Also nimm jenes. Und zuletzt klicken wir auf Projekt erstellen, damit das Projekt entsteht. Ich schließe hier das Terminal, indem ich auf die drei Punkte klicke. Dann öffne ich das Terminal und klicke auf den Papierkorb. Und wie Sie sehen. Wir haben dort unseren neuen Game-Store-API-Ordner, der unser .NET-Projekt enthält, der hier liegt, zusammen mit einer ganzen Reihe weiterer Dateien, die unsere bisherige .NET-Anwendung vollständig ausmachen. Bevor wir uns die erzeugten Dateien im Detail ansehen, gibt es zwei Wege, wie man diese Projektdateien sinnvoll durchsuchen kann. Der erste Weg besteht darin, den Dateiexplorer zu verwenden, den du standardmäßig geöffnet vorfindest. Also hier ist dein Dateiexplorer, und hier handelt es sich um eine physische Ansicht. Damit wird wirklich jede einzelne Datei deines Projekts sichtbar gemacht. Wie Sie sehen können, betreffen Ihre Lösungsdatei und sogar Ihr Dasein als OVA-Verzeichnis hier nicht das Thema, das man gleich besprechen wird; aber es gibt auch noch etwas. Eine weitere Ansicht, bekannt als Lösungs-Explorer, die Sie unten sehen können. Wenn Sie dies erweitern, und vielleicht klappen wir es kurz zusammen, hier ist der Lösungs-Explorer. Dies stammt vom C# Sharped Kit, und dies wird eher eine virtuelle Ansicht Ihrer Anwendung sein. Was nur die schnellere Version zeigt, die vor allem für Ihre C#- und R-Entwicklung relevant ist, Und dir die Fähigkeit geben, einfach mit dem Erstellen zu beginnen. Verschiedene C#-R-Dateien. Zum Beispiel kannst du hier rechts klicken und Dateien erstellen, wie du siehst. Und du kannst Beziehungen zwischen Projekten herstellen, NOGA-Pakete installieren und ein paar weitere Dinge. Wir verwenden in diesem Kurs beide Explorer-Ansichten, doch die meiste Zeit bevorzuge ich hier den Datei-Explorer, weil er sehr übersichtlich zeigt, was in diesem Projekt geschieht. Nun gehen wir die erzeugten Dateien durch und sehen uns die C-Programme an, das ist die einzige Quelldatei, die wir haben. Lass mich das hier zusammenklappen. Und der Zweck dieser Datei besteht darin, den Code festzulegen, der Ihre Anwendung startbereit macht Insbesondere ist das Hauptziel hier, eine Instanz dieses App-Objekts zu erstellen, das tatsächlich als Webanwendungsobjekt fungieren wird. Wie Sie sehen können, möchten wir eine Instanz der Webanwendung erzeugen, und am Ende hier möchten wir sie ausführen, ganz konkret. Aber was ist diese Webanwendung hier drüben, die wir als Host kennen? Dies ist der Host deiner App, und der Zweck davon ist es, eine HGTP-Server-Implementierung für deine App einzuführen, damit du beginnen kannst, HG-HTTP-Anfragen abzuhören. Nun, wie Sie sehen, erstellen wir nicht einfach direkt die Web-App-Optik. Stattdessen nutzen wir Builder-Muster über diesen Create-Builder-Optic hier. Und das liegt daran, dass wir dieses Builder-Objekt verwenden, um eine Reihe von Diensten für die App zu konfigurieren. Wie Sie es mit dem Builder jederzeit tun können, und Sie werden sehen, dass hier viele Funktionen und Methoden gibt. Um Dienste, Konfigurationen und vieles für App festzulegen, wie wir sie in Scores sehen. Von dort rufen wir die Build-Methode auf, die zudem mit einer Reihe von Standardeinstellungen für unsere Anwendung kommt, etwa die Nutzung des Castrale-Webservers. Das Auslesen von Einstellungen aus Apps, JSON-Datei oder Umgebungsvariablen, und wie Login-Dienste konfiguriert werden. All das passiert durch den Build-Aufruf hier, der das Web-App-Objekt erzeugt. Also dieser Abschnitt hier, zwischen Zeile eins und … Ein Abschnitt, in dem wir alle Dienste der Anwendung konfigurieren. Und dann, sobald die Anwendung vorhanden ist, wechseln wir in den zweiten Abschnitt über, in dem festgelegt wird, was in der HTTP-Pipeline geschieht, also was passieren wird, wenn diese HTTP-Anfragen in die Anwendung gelangen. Zum Beispiel hier drüben, standardmäßig, wie man sehen kann. Wir definieren, dass eine Anfrage, die über GET Burp an die Anwendung gerichtet wird – die ROT-Anwendung –, einfach mit einer einfachen Hallo-Welt-Zeichenkette beantwortet wird, die dann wieder in die Farbe zurückkehrt. Und die letzte Zeile hier wird nun den Start der Ausführung der Anwendung auf dem Castrale-Webserver einleiten. Wir werden im Verlauf der Punkte noch viel mehr über Pro Cs erfahren. Vorerst schließen wir das. Gehen wir in unseren Datei-Explorer zurück und werfen wir kurz auf unseren Spielstore, API und CS-Profil. Dies wird als die Projektdatei bezeichnet. Die Datei ist allen Netzanwendungen gemeinsam, in diesem Fall. Es enthält genau diesen SDK-Eintrag, der Microsoft .NET verwendet, das SDK-Web. Dies legt fest, um welchen Typ von Anwendung es sich hier eindeutig handelt, in diesem Fall eine Webanwendung. Äh, dies wird alle Bibliotheken importieren, die speziell für .NET-Webanwendungen entworfen wurden. Noch eine wichtige Sache hier: Das Ziel-Framework. Wie Sie hier sehen können, Das Ziel-Framework bestimmt die APIs, die Ihrer Anwendung zur Verfügung stehen. Wenn Sie eine niedrigere Version verwenden, haben Sie weniger APIs zur Verfügung; bei einer höheren Version stehen Ihnen mehr und neuere APIs zur Verfügung. In diesem Fall verwende ich .NET 10, wie man dort sieht, ganz deutlich, denn das ist die Version. Ich nutze es Standard, als ich Projekt machte. Jetzt schließen wir das hier und gehen in unsere appsettings.json, diese JSON-Datei hier. Diese Datei und auch appsettings.json für die Entwicklung sind die Dateien, die du verwenden kannst, um Konfigurationen zu definieren, die du nicht hart in deinem C#-Code codieren willst. JSO ist Standarddatei, die verwendet wird. In jeder Umgebung gibt es außerdem ABS-Abwesenheit der JSO-Entwicklung, die du lokal verwenden kannst. Jetzt begeben wir uns hier in den Ordner Eigenschaften, dort werden wir die andere Datei namens Launch Set Jason finden. Und dies ist eine Datei, die eben entworfen wurde. Um festzulegen, was Profile bedeuten. Das Profil ist ein Ort, an dem man Einstellungen festlegen kann. Es geht darum, wie Sie Ihre Anwendung in der lokalen Entwicklung ausführen. Alles, was hier definiert ist, gilt ausschließlich für die lokale Entwicklung und hat nichts mit Produktion zu tun. Hier definieren wir es eben. Wenn wir die Anwendung über HTTP starten möchten, wird die URL der Anwendung hier zu sehen sein, HTTP, localhost 51 59. Der Port wird zufällig festgelegt, wenn du ein Projekt erstellst, daher bekommst du wahrscheinlich einen ganz anderen Port. Wenn du deine eigene Anwendung erstellst, Sie können hier Umgebungsvariablen definieren, zum Beispiel diese Finnet-Umgebungsvariable, die anzeigt, dass wir in einer Entwicklungsumgebung arbeiten, nicht in der Produktionsumgebung. Wenn Sie lokal H-G-T-P-S verwenden möchten, nutzen Sie Ihr H-G-T-P-S-Profil, das eine URL mitbringt. Wie hier zu sehen ist, haben wir H GT P. S, Localhost 7083, wodurch du deine Anwendung lokal mit HTTPS ausführen kannst. Okay, jetzt schließen wir das hier endgültig ab. Und noch ein paar andere Dinge, die hier genau zu beachten sind: Der Anteil davon, insbesondere, dass es sich um OVA-Verzeichnisse handelt, wobei hier OVJ die Zwischendateien enthält, die von .NET erzeugt werden, bevor die endgültige Version Ihrer DLL erstellt wird. Und diese endgültige Version wird wirklich hier in diesem Bin-Verzeichnis landen. Zuletzt, wie hier unten zu sehen ist, haben wir unsere S-SLX-Datei, diejenige ist. Es versteht, welche Projekte du hier in VS Code bearbeitest und wie sie zusammenhängen. Die Datei treibt das Nutzererlebnis an, das du hier unten im Explorer siehst. Wir werden im Kurs deutlich mehr über alle diese Dateien lernen. Jetzt, da wir die Struktur unseres .NET-Projekts verstehen, schauen wir, wie man die Anwendung baut und ausführt. Und beginnen wir mit dem Aufbau der Anwendung. Wie bauen wir das? Nun, es gibt einige Wege. Ich denke, der einfachste Weg ist, den Solution Explorer zu verwenden, damit du im Solution Explorer arbeiten kannst. Dort klappe ich es kurz zusammen. Und hier musst du nur mit der rechten Maustaste auf dein Projekt klicken. Store-API, rechts. Dort klickst du dann bitte auf die Build-Option. Wie du rechts sehen kannst, öffnet sich ein Terminal, und unsere Anwendung wurde gebaut und hat es produziert. Die Apple-DLL ist dort. Du kannst den Prozentsatz dieser DLL prüfen, indem du in den Datei-Explorer gehst. Du kannst ins Bin-Verzeichnis gehen, dort findest du deine DLL und weitere Dateien. Eine andere Möglichkeit, das zu tun, besteht darin, dein Terminal direkt zu verwenden, richtig? Also lasse ich mich hier tatsächlich auf ein brandneues Terminal umschalten; ich klicke dort auf das Pluszeichen, um ein brandneues Terminal zu starten. Und das andere beende ich, um mehr Platz zu haben. Und von hier aus kannst du in dein Game Store dot AP-Verzeichnis wechseln, und du kannst .NET C# verwenden. Mit dem Build-Befehl wird es gestartet, und damit wird Ihre Anwendung direkt vom Terminal zügig aufgebaut. Dazu können Sie diese Vorgehensweise sowohl innerhalb von Business Studio Code als auch außerhalb davon ausführen. Zuletzt können Sie außerdem ganz einfach die Integration von .NET in den Build-Task in VS Code verwenden. Sie können dann ganz bequem Strg+Shift+B drücken, und damit wird der Build-Task in VS Code sofort geöffnet. Sie können auf .NET Build klicken, bitte jetzt. Und das wird erneut den Build Ihrer Anwendung starten, heute. Wie Sie sicher deutlich gesehen haben. Jetzt, wie man die Anwendung ausführt. Genau wie beim Erstellen der App gibt es auch viele Wege, die Anwendung in VS Code auszuführen; ich halte jedoch F5 tatsächlich für den einfachsten Weg. Also drücken wir F5, und beim ersten Mal, wenn du das machst. VS Code wird dir zwei Fragen stellen. Zuerst will VS Code wissen, welche Art Anwendung du ausführen willst, damit es Werkzeuge für Ausführung nutzt. In unserem Fall wird es eine C#-Anwendung sein, also wählen wir hier C#-Sharp. Als Nächstes fragt VS Code nach unserer Launch-Konfig. Es gibt hier mehrere Optionen, doch die wichtigsten sind jene, die sich auf unsere Startprofile beziehen, die wir in unserer Startserie gesehen haben, und die benachbarte Datei, bitte beachten. Hier können wir HTTP-Profil starten; danach sehen wir das HTTPS-Profil, das wir starten können. Für den Zweck dieses Kurses, um die Dinge einfach zu halten und jegliche Zertifikatsprobleme zu vermeiden, wählen wir die HTTP-Option, die auch der Standardkonfiguration entspricht. Also klicken wir auf HTTP. Und in diesem Moment wird Visual Studio Code zuerst das Projekt erneut bauen und dann mit der Projektausführung beginnen. Beachten Sie, dass VS Code nicht nur unseren Webserver gestartet hat, sondern auch einen Browser geöffnet hat, um in das Stammverzeichnis der Anwendung zu gelangen. Und wie Sie sehen, hier HelloWorld. Der Grund, HelloWorld zu sehen, ist erneut; schauen wir uns unsere Pro-CS-Datei an. Gehen wir zurück in unsere Haupt-CS-Datei. Lassen Sie mich das kurz zuklappen. Wir merken uns ja, dass wann immer eine GET-Anfrage an der Wurzel der App eingeht, die App erwartet, das Wort 'world' im Klartext zurückzugeben, wie dort zu sehen ist. Jetzt ist Folgendes zu beachten: Wir führen die Anwendung nicht nur aus, sondern befinden uns im Debug-Modus, was bedeutet, dass wir Haltepunkte setzen können, um den Zustand der Anwendung während der Ausführung zu prüfen. Um das zu zeigen, stoppe ich die Anwendung kurz. Dann können wir hier auf den Stop-Button klicken, um das Debuggen zu beenden und die App zu stoppen. Setzen wir hier in der fünften Zeile einen Breakpoint. Lass uns das Debuggen erneut starten. Jetzt: Statt Fünf zu drücken, zeige ich dir eine andere Möglichkeit, zu debuggen. Öffne den Lösungs-Explorer. Lass es hier zu. Mit der rechten Maustaste auf deine Game-Store-API klicken und Debug-Auswahl treffen. Starte eine neue Instanz. Es ist derselbe Effekt wie das Drücken der F5-Taste. Es ist nur eine andere Art, es eben zu tun. Beachten Sie bitte jetzt: Wir ziehen hier etwas zusammen, greifen in die laufende Anwendung ein und untersuchen die Objekte, die gerade aktiv sind. Wenn wir über 'up' hovern, sehen wir dort Eigenschaften, die sich auf das App-Objekt beziehen. Hier drüben, ja. Auch links sehen wir. Die hier lokalen Variablen, richtig? Einschließlich unseres Builders und aller seiner Eigenschaften der App. Wir könnten Beobachtungs-Ausdrücke verwenden; bei Bedarf zeigen wir auch den Aufrufstapel. Sie verfügen jetzt über vollständige Debugging-Unterstützung in VS Code. Um die Ausführung fortzusetzen, werde ich hier auf den Play-Button klicken. Wir klicken dort hinein, und dieses Mal öffnet der Browser erneut, wie Sie sehen können, und es ist tatsächlich wieder gestoppt, denn wenn Sie zu VS Code zurückgehen, passiert Folgendes: Wir befinden uns dieses Mal nicht in der Startup-Sequenz, sondern im Handler für das GET-Verb. Der Browser stellte eine GET-Anfrage an die Startseite der App, und diesmal prüfen wir diesen Schritt, der die Antwort liefert. Hallo? Kehren Sie zurück, Herr. Wir erfahren bald, wie dieses Karten-Tor funktioniert. Später im Kurs, aber vorerst klicken wir einfach noch einmal auf den Weiter-Button. Und zurück im Browser sehen wir dort erneut Hallo Welt. Auch wenn es sehr nützlich sein kann, deine Anwendung mit einem angehängten Bug zu starten, gibt es einen deutlich schnelleren Weg, deine App für deinen normalen Entwicklungsablauf zu starten. Wenn du wieder in VS Code gehst, stoppen wir die Anwendung erneut. Klicke erneut auf Stopp. Schließe dies. Und Sie können wirklich einfach die App starten, ganz ohne Debugger. Und was Sie tun können, ist in den Datei-Explorer zu gehen, hier in den Solution Explorer, Rechtsklick auf Game Store API, und dann wählen Sie jetzt 'Ohne Debuggen starten'. Klicken Sie dort bitte. Dadurch wird die Anwendung erneut gestartet; diesmal ist Novo angehängt. Wie Sie gesehen haben, ist es deutlich schneller, wirklich sehr. Es ist nicht nötig, die Live-Ausführung der App zu prüfen. Das ist eine Möglichkeit, es zu tun. Eine weitere Möglichkeit besteht darin, es erneut zu stoppen, indem man STRG-F5 drückt. Du kannst STRG-F5 drücken; das hat denselben Effekt. Sehr einfach, dorthin zu gelangen, wie man sieht. Und der letzte Weg besteht darin, C# direkt im .NET zu verwenden. Nun bevor ich Ihnen das zeige, stoppen wir das hier noch mal. Was ich zeigen will, ist, dass es eine Möglichkeit gibt, zu verhindern, dass dieser Code den Browser öffnet. Wie Sie sehen, sind hier mehrere Tabs offen. Was nicht nur nicht ideal ist, aber wir arbeiten auch an einer serverseitigen Res-API. Das lässt sich direkt in VS Code auf einfachere Weise testen, ohne den Browser zu verwenden. Und ich werde dir später im Kurs noch ausführlich mehr dazu zeigen. Aber vorerst können wir in VS Code gehen und dieses Mal in unseren eigenen Datei-Explorer wechseln. Gehen wir in Eigenschaften und starten das hier bei Jason gleich. Und auch hier. Wenn wir wieder in unser HTTP-Profil gehen, ist das hier unser HTTP-Profil. Wir werden hier diese Eigenschaft finden, die 'Launch browser' sagt 'durch'. Was wir tun können, ist einfach, das von Durch auf Puls umzuschalten. damit VS Code den Browser nicht mehr öffnet und uns in der VS Code-Umgebung dauerhaft belässt. Also diesmal, wenn ich F5 drücke, drücke ich F5 erneut. Hier seh ich, wie die App läuft, und wir bleiben ganz im Kontext von VS Code, ohne Unterbrechung. Kein Grund mehr, den Browser zu öffnen. Okay, jetzt starte ich die Anwendung, und wie ich schon gesagt habe, kannst du sie auch mit .NET C# ausführen. Dafür öffne ich hier. Lass mich in mein Terminal wechseln. Ich beende dieses Terminal kurz. Ich lösche den Bildschirm und vergrößere das hier ein wenig, noch ganz leicht. und Wohlbefinden im Game Store API-Verzeichnis, an dem Ort, an dem unser Projekt lebt. Was du tun kannst, ist praktisch ganz einfach zu sagen, net run, und Enter zu drücken. Nochmals, das wird die Anwendung aufbauen und sie dann starten. Und wie du deutlich sehen kannst, Die Konsolenausgabe meldet den Ort unserer API, dort – Localhost, 51 59; wir sehen, dass die App gestartet wurde. Wir sehen unsere Hosting-Umgebung, die zurzeit nur Entwicklung ist. In unserem Inhaltspfad hier, genau hier, Ich bevorzuge diese Methode, um meine Domänen-App zu starten, weil ich sofort sehe, was los ist, wenn ich hier die Konsole anschaue. Oder nutze andere Optionen, falls sie dir besser passen. Da wir nun wissen, wie wir unsere Anwendung bauen und starten, wechseln wir kurz zu den Folien, damit wir REST-APIs verstehen. Um zu verstehen, was REST-APIs sind, fange damit an, darüber nachzudenken, welche Apps du auf deinem Telefon hast, wie Wetter-, LinkedIn- oder Spotify-Apps. Diese Apps benötigen eine Menge Daten, doch diese Daten passen nicht auf dein Telefon; das nennen wir Client. Es ist zu viel, sie zu speichern, und du willst ohnehin laufend aktuelle Daten, immer neue Daten. Also müssen die Daten von irgendwoher kommen, und der Ort ist eine Art Server-Rechner, der normalerweise in der Internet-Cloud liegt. Aber wie können diese Apps mit diesem Server in der Cloud kommunizieren, um die Daten abzurufen? Nun, durch die Verwendung einer API. API steht für Application Programming Interface, und es ist so, wie ein Dienst die Funktionen definiert, die er seinen Kunden bereitstellt. Wenn man zum Beispiel zum Spotify-Beispiel zurückkehrt, könnte der Spotify-Cloud-Dienst eine API mit zwei Funktionen definieren. Die Funktion zum Abrufen der neuesten Songs, nimmt den Benutzernamen als Parameter und liefert die zehn neuesten Songs des angegebenen Nutzers zurück. Und es könnte auch eine Abspiel-Funktion geben, die den Songname als Parameter erhält und auch den Stream dieses Songs zurückgibt, damit ein Client ihn abspielen kann. So könnten dutzende oder hunderte Funktionen vom Dienst angeboten werden, die Kunden nutzen, um mit ihm zu interagieren. Eine API hilft den Kunden, dem Service mitzuteilen, was sie wollen, damit er versteht und die Anfrage erfüllen kann. Ich. REST steht für Representational State Transfer und auch definiert eine Reihe von konkreten Leitprinzipien, die festlegen, unter welchen konkreten Bedingungen eine API funktionieren sollte. In diesem Kurs gehen wir nicht auf jedes dieser Prinzipien ein, doch wichtig ist, dass man APIs auch bauen kann, die skalierbar, flexibel und technologieunabhängig sind, und auf dem Server wirklich funktionieren. Also nochmals zurück zur ursprünglichen Frage: Eine REST- oder RESTful-API folgt dem REST-Architekturstil. Der Hauptgrund dafür, warum wir eine REST-API einrichten möchten, besteht darin, dass unsere Clients mit den von der API verwalteten Daten interagieren können; aber wie greifen sie tatsächlich auf diese Daten zu? Nun ist es wirklich sehr hilfreich, zunächst das Konzept einer Ressource in einer REST-API zu verstehen. Eine PIA-Ressource ist jedes Objekt, Dokument oder Ding, das die API von Clients empfangen oder an Clients senden kann. Zum Beispiel ist in unserer Spielstore-Anwendung die Hauptressource unsere Gewinne. Das ist das, was die Clients abfragen und ändern wollen. Aber in anderen Anwendungen, wie dem Spotify-Beispiel, könnte eine der Ressourcen die Songs sein. Und im LinkedIn-Beispiel könnte eine Ressource die Nutzer sein, und eine weitere die LinkedIn-Beiträge. Diese Ressourcen werden auf einer Domain gehostet, die öffentlich sein könnte, oder auf einem Intranetstandort – oder eben Ihre Deb-Box. Und sie können über das HTTP- oder HTTPS-Protokoll aufgerufen werden, was in öffentlichen Umgebungen ein Muss ist. Wenn man all diese Dinge kombiniert, erhält man die URI (Uniform Resource Identifier), die Ihre Clients verwenden, um die Ressourcen der REST-API zu identifizieren und darauf zuzugreifen. Es könnten weitere Teile dieser URI existieren, aber dies sind Kernbausteine. Nun, wie interagiert man eigentlich mit der REST-API? Genau wie bei alten Webseiten: Wenn Clients etwas vom Server anfordern möchten, senden sie eine HTTP-Anfrage über die passende URI an den Server, und der Server antwortet danach mit einer Antwort. Allerdings sehen REST-APIs und Anfragen sowie Antworten je nach der verwendeten HTTP-Methode, mit der sie aufgerufen werden, etwas unterschiedlich aus. Die gängigsten Methoden sind POST, mit denen neue Ressourcen erstellt werden, GET, das die Repräsentation oder den Zustand der Ressource abruft, PUT, das eine vorhandene Ressource aktualisiert, und DELETE, das die Ressource löscht. Diese Methoden ermöglichen, Ressourcen zu erstellen, zu lesen, zu aktualisieren und zu löschen. Und daher sind sie ebenfalls allgemein als Crowd-Operationen bekannt. Es gibt auch andere Methoden, aber für die Zwecke dieses Kurses liegt der Fokus auf diesen vier Methoden. Lassen wir uns die Ansätze im Kontext unseres Spielladens ansehen, um zu sehen, wie sie funktionieren. Ich. Um alle Spiele abzurufen, sendet ein Client eine GET-Anfrage an den Spiele-Endpunkt, und der Server wird bitte mit so etwas antworten. Der erste Teil dieser Antwort ist der Status, der 200 beträgt. Okay. In diesem Fall bedeutet dies, dass der Vorgang ein Zugriff war. Es gibt andere HTTP-Statuscodes, die API je nach dem Ergebnis der Operation zurückliefert; viele sind Fehlerfälle. Der nächste Teil ist der Körper, der die Liste der Spiele enthält. In diesem Fall ist zu beachten, dass dieser Körper kein HTML ist, sondern das Format der Antwort als JSON bekannt ist. JSON steht für JavaScript-Objektnotation. Dies ist das De facto Format zum Senden und Empfangen von Daten in REST-APIs, da es so leicht zu lesen und zu schreiben ist und von allen gängigen Programmiersprachen unterstützt wird. Wenn Sie statt aller Spiele ein bestimmtes Spiel erhalten möchten, würden Sie erneut eine Abfrage senden, aber diesmal hängen Sie am Ende den Bezeichner der Forschung an, Nummer eins. In diesem Fall wird der Server den Zustand des Spiels zurückmelden. Mit diesem Bezeichner, vorausgesetzt, dass er ein Spiel finden kann. Um ein Spiel zu erstellen, kann der Client erneut eine POST-Anfrage senden, die auf die Games-Ressource oder URI verweist; diesmal muss im Anfragetext der gewünschte Zustand der Ressource angegeben werden, der in diesem Beispiel nur den Namen des Spiels enthält, aber auch weitere Eigenschaften umfassen könnte. Der Server antwortet in der Regel mit dem Statuscode 201 Created, falls der Ressourcen-Identifier im Anfragetext nicht angegeben wurde. Die Antwort enthält es meist. Um ein bestehendes Spiel zu aktualisieren. Der Client sendet eine PUT-Anforderung mit derselben Ressource bzw. derselben URI wie zum Abrufen eines Spiels, doch diesmal enthält sie den Zustand der Ressource, ganz ähnlich dem POST-Szenario. Diese Nutzlast wird den Zustand des Spiels, das mit einer bestimmten Kennung verknüpft ist, vollständig ersetzen und wird typischerweise nur mit dem Statuscode 204 No Content antworten. Zuletzt sendet der Client eine zentrale Löschanfrage an die URI, die das zu löschende Spiel identifiziert. Nachdem die Ressource gelöscht wurde, antwortet der Server normalerweise mit dem Statuscode 204 No Content. Also kurz gesagt wird Ihre REST-API für Spiele so aussehen und den Support liefern, den Ihre Kunden von modernem Backend erwarten. Lassen Sie uns im Code schauen, wie man diese API in HV net core implementiert. Bevor wir unsere Game-Store-REST-API implementieren, Lassen Sie mich Ihnen zeigen, wie Sie mit Ihrer REST-API in VS Code interagieren können, ohne dabei einen Browser verwenden zu müssen. Und dazu installieren wir eine neue VS Code-Erweiterung. Also gehen wir jetzt bitte in den Erweiterungsbereich von VS Code. Und diesmal suchen wir nach REST Client, der hier drüben ganz einfach zu finden ist. Rest Client von wa MAO gehört zu den beliebtesten Erweiterungen, um REST-APIs zu verwenden, auch wenn es nicht die einzige ist. Es gibt viele davon. Aber ich mag dieses hier, weil es so leicht zu bedienen ist. Klicken wir auf Installieren. Und jetzt gehen wir in unseren Dateiexplorer. Lass uns das hier schließen. Und wozu diese Erweiterung gut ist: Wir erstellen eine Datei, in der wir Anfragen an unsere API definieren können. Also klicken wir im Dateiexplorer erneut auf Game Store API. Dann klicken wir auf Neue Datei. Und lass uns der Datei den Namen 'games' geben, http. Und hier können wir das Verb und den Ort des API-Endpunkts genau definieren, den wir aufrufen möchten. In unserem Fall haben wir derzeit, wie wir uns erinnern können, in Program Cs unseren GET-Endpunkt an der Wurzel, der mit Hallo Welt antworten wird. Richtig? Also kehren wir nun zurück zu Games HGTP, was wir tun können, ist, einen GET-Aufruf mit dem Ort unseres Lokale Anwendung, die HTTP sein wird. Schrägstrich Schrägstrich. Und wie lautet der Standort? Nun: Um sich daran zu erinnern, gehen Sie jederzeit in die Eigenschaften – Launch Series bei Jason – und merken Sie sich, dass dieser Ort hier für Ihr HTTP-Profil in der Anwendung vorgesehen ist. Die hier genannte URL ist localhost und Port, bitte. Also kopierst du das hier in Games, dieses HTTP-Ding dort drüben. Und jetzt befinden wir uns in der Lage, unsere API direkt aus VS Code aufzurufen. Nun, bevor wir dies tun, öffne ich mein Terminal, ich wechsle zur Game-Store-API, und wir führen dotnet run aus. Okay, ganz sicher. Die Anwendung ist erfolgreich gestartet. Beachte bitte, dass sie tatsächlich zuverlässig läuft, und zwar am Port 51, 59. Also legen wir jetzt los und klappen das hier ein wenig zusammen. Und klicken wir hier, um zu sehen, was dort steht. Anfrage senden. Klicken wir dort. Und wie du rechts siehst, klappe ich das jetzt zu. Jetzt sehen wir alle Details der Antwort, die unsere Anwendung an den Client zurückgeschickt hat, inklusive unseres Statuscodes. Wir sehen den Statuscode zweihundert. Okay. Dort zurück. Wir sehen den Inhaltstyp, der derzeit nur Text ist, und auch ein paar weitere Dinge. Im Kern geht es um die eigentliche Antwort, die von unserer API zurückkommt. Das ist eine deutlich bessere Art, über MVS-Code mit Ihrer API zu interagieren. Dabei müssen Sie nicht ständig Browser öffnen. Jetzt schließen wir das hier. Schließen wir auch das. Und verwenden wir außerdem die innere C#-Steuerung, um den Server zu stoppen. Ich werde dieses Terminal vorerst beenden, und schauen wir uns unsere CS-Datei an, um zu sehen, wie wir unseren ersten API-Endpunkt implementieren können. Jetzt entferne ich diesen Breakpoint und öffne hier eine Zeile, um zu beschreiben, welcher Art Endpunkt es ist, den wir implementieren werden. Es handelt sich dabei um einen GET-Endpunkt, der zu jedem beliebigen Zeitpunkt alle Spiele zurückgibt, die in unserer API verfügbar sind. Und der eigentliche, exakte Ort, an dem diese Ressourcen künftig leben werden, wird unter Games liegen. Ich. So teilt man ASP.NET Core mit, was zu tun ist, wenn eine HTTP-Anfrage in unsere API kommt, durch MapGet-Methode, die wir hier definiert haben; bisher reagiert sie nur darauf. Zwei Zugriffe auf den Wurzelpfad der Anwendung, der hier auf dieser Folie zu sehen ist. Also wird der erste Parameter, den wir hier haben, das Muster sein, das durch diese Map-Methode abgeglichen wird. In unserem Fall möchten wir natürlich ändern, dass statt einfach auf die Wurzel zu gehen das Muster Slash-Games sein soll. Nun wird der zweite Parameter dieser Methode als der Handler bezeichnet. Dies ist also der Handler, der dem Finnet-Kern mitteilt, was zu tun ist, wenn eine Anfrage eintrifft und in dieses Muster passt, das wir auf der linken Seite finden. Ich. Zu diesem Zeitpunkt sagt der Handler nur, dass wir den Hallo-Welt-String an den Client zurückgeben wollen. Natürlich wollen wir jetzt die Liste der Spiele, die von der API verfügbar sind, zurückgeben. Bevor wir die Liste der Spiele zurückgeben können, müssen wir eine Darstellung dieser Spiele festlegen, die an den Client zurückgegeben wird. Dafür müssen wir klären, was ein Data-Transfer-Objekt (DTO) ist. Um unser DTO zu erstellen, gehen wir in unseren Solution Explorer. Also öffnen wir den Solution Explorer jetzt wirklich. Klappen wir es zu. Klicken wir rechts auf Game Store API und erstellen einen ganz neuen Ordner, den wir Dios nennen. Dann klicken Sie mit der rechten Maustaste auf DTS und wählen Neue Datei. Hier gibt es Optionen, um C#-TO zu erstellen. Wir könnten dafür eine Klasse verwenden, doch ich bevorzuge hier einen Record-Typ. Und das liegt daran, dass Datensätze sich gut eignen, Dinge zu zeigen. Einfache Daten, die von Ort zu Ort wandern, ohne Änderung. Und sie reduzieren Boilerplate-Code, typischerweise nötig bei Klassen. Benennen wir den Datensatz erneut. DTO ihi. Eingeben. Öffne es im Editor und mach das hier zu. Lass mich jetzt meine Aktivitätsleiste ausblenden, damit wir hier ein wenig mehr Platz bekommen, so wie hier nun. Und nun ist die Frage, was hier in unser neues Spielvideo eingefügt werden soll. Ich füge hier einen kurzen Kommentar ein; ADIO ist wirklich ein Vertrag zwischen Client und Server, der eine gemeinsame Vereinbarung darüber darstellt, wie diese Daten übertragen und verwendet werden sollen. Im Wesentlichen möchten wir hier alle Eigenschaften genau auflisten, die wir dem Client zurückgeben, wenn dieser unsere Liste der Spiele anfordert. Nun gibt es Wege, Record-Typen in C# darzustellen. Das Erste, was zu beachten ist: Man kann sie als Record-Klasse definieren oder einfach 'record' sagen. Es ist sozusagen ein Synonym der Record-Klasse, daher bleibt es einfach. Außerdem lässt sich diese Eigenschaften hier in geschweiften Klammern definieren. Aber einen einfachen Weg gibt es: APIs hier zu verwenden und Eigenschaften direkt festzulegen. Also schick ich das hier in die nächste Zeile und schließe es dort ab. Und lass unsere erste Eigenschaft definieren: Die Kennung unseres Spiels ist eine interne ID. Sie ist die ID. Der nächste Schritt wird der Name unseres Spiels sein. Danach werden wir außerdem auch das Genre unseres Spiels festlegen. Der Spielpreis wird voraussichtlich als klarer Preis im Dezimalformat festgelegt, deutlich. Und schließlich werden wir zusätzlich unser Veröffentlichungsdatum angeben, das nur das Datum umfasst. Damit ist unser erster DTO definiert, und wir können ihn jetzt auch schon ganz sicher im neuen API-Endpunkt verwenden. So schließen wir das hier – zurück zu Prod.-CS. Bevor wir diese Spiele über den Endpunkt an den Client zurücksenden können, benötigen wir eine Spielesammlung, um sie zurückzugeben. Um es an dieser Stelle einfach zu halten, werden wir diese Ansammlung von Spielen einfach als eine schlichte Liste darstellen, die wir direkt hier in dieser Datei definieren. Und später im Kurs werden wir sehen, wie man davon zu einer echten Datenbank übergeht. Also hier in Zeile fünf werde ich eine brandneue Liste von Game-DTOs definieren, das ist unser neuer Typ, für den ich hier etwas ausführen muss, nur mit C#, um meinen GameStore-API-DTO-Namensraum verwenden zu können. Lass uns das als Spiele festlegen. Okay, also hier legen wir unser erstes Spiel fest. Ich scrolle ein wenig nach unten. Lass uns es neu definieren. Spiel mit Idee Nummer 1. Der Name wird letztendlich State Fighter zwei heißen. Das Geschlecht wird beim Kämpfen beteiligt sein. Der Preis wird neunzehn neunundneunzig betragen. Und das Datum wird künftig nur ein neues Datum sein, das eindeutig dem Jahr 1992 zugeordnet ist. Monat sieben, und der Tag fünfzehn. Und ich schicke das auf die nächste Folie, damit wir es hier wirklich besser sehen. Und wir sehen, dass dort der Preis ein Problem ist. Und das ist der Grund. Der Compiler wird bei dieser Zahl leicht verwirrt. Er weiß nicht, ob wir hier Double- oder Dezimalzahl verwenden. Da wir das nun als Dezimalzahl festlegen, hilft dem Compiler, indem wir hier einfach den Buchstaben M hinzufügen, und das zeigt, dass wir die Zahl als Dezimalzahl verwenden möchten. Jetzt ist es wohl besser, nicht nur mit einem Spiel zu arbeiten, sondern mit mehreren. Noch ein paar weitere Spiele. Ich füge aus der Zwischenablage hier ein. Okay, also haben wir nicht nur eins, sondern drei Spiele. Wir haben unser zweites Spiel. Es wird Final Fantasy, sieben Revert, RPG. Hier der Preis und das Datum. Zuletzt haben wir unser After-Bot-Spiel. Das dritte Spiel wird Plattform-Spiel sein. Hier Preis und Veröffentlichungsdatum. Wie gesagt, verwenden wir im ersten Teil dieses Kurses diese Spiel-Liste, indem wir einfach eine Merkliste von Spielen hinzufügen, und später wechseln wir zu einer echten Datenbank. Jetzt, wie verwenden wir diese Spiel-Liste denn mit unserem API-Endpunkt? Nun scrollen wir ein wenig nach unten. Wir müssen nur unseren Handler aktualisieren. Hier ist ein langer Ausdruck, um es ihm mitzuteilen, dass wir nicht mehr zurückkehren möchten. Hallo Welt, stattdessen geben wir unsere Spieleliste so zurück. Es gibt hier viele Wege, deinen Handler zu definieren; einer der einfachsten. Jetzt führen wir die Anwendung aus und sehen, was passiert, wenn wir unseren neuen Spiele-Endpunkt aufrufen. Ich öffne hier mein Terminal. Ich wechsle zum Game Store API. Nochmal führe ich es nun aus. Okay, es läuft. Schließe das Terminal kurz, dann kehre ich zum Datei-Explorer zurück. Ich drücke Strg, Umschalt und E, um meinen Explorer zu öffnen. Sehr schnell wechsle ich kurz in den Datei-Explorer, nicht in den Lösungs-Explorer. Ich öffne die HTTP-Datei. Ich modifiziere die hier vorliegende Anfrage geringfügig, damit sie auf unseren Games-Endpunkt verweist. Denk daran, dass unser Endpunkt jetzt unter /games liegt; daher kopiere ich ihn auch. Ich füge ihn hierhin direkt nach dem Host-Import ein. Und nunmehr sind wir bereit, unseren Games-Endpunkt aufzurufen. Also klicken wir hier, um eine Anfrage zu senden, und auf der rechten Seite sehen wir unseren Statuscode 200. Okay. Dies war eine erfolgreiche Antwort. Dieses Mal erhalten wir den Inhaltstyp application/json, weil wir jetzt eine Sammlung von Objekten zurückgeben, die standardmäßig von ASP.NET Core in eine JSON-Antwort transformiert werden kann. Und hier unten können wir die JSON-Antwort sehen. Be achten Sie ja, dass dies ein Array ist, in dem jedes Element eines unserer Gewinne sein wird; wir speichern es vorerst in unserer API im Speicher. Hier sind Spiel eins, zwei und drei. Unser erster Endpunkt läuft wie erwartet. Nun schauen wir, wie wir diesmal einen zweiten Endpunkt einbauen, um nur ein Spiel abzurufen statt der Liste der Spiele. Dazu schließen wir das. Also stoppen wir unseren Server. Ich drücke hier Strg+C, schließe das Terminal und kehre zum Programm C# S zurück. Für unseren neuen Endpunkt verwenden wir dieselbe Idee wie beim ersten. Wir fügen hier ein paar Zeilen hinzu. Wir fügen etwas Dokumentation hinzu. Das ist wirklich optional. Ich mache das gern, damit ich genau weiß, was ich von diesem Endpunkt erwarten kann. Dieser Endpunkt zielt erneut auf das Gamepad, und am Ende geben wir die Route an. Die Spiel-ID, die wirklich abgerufen werden soll. Wenn du Nummer Eins abrufen willst, geben wir hier die Eins durch. So ist der korrekte Weg, RESTful Weg, um eine Ressource über ihre eindeutige Kennung abzurufen. Also, um das umzusetzen, erstellen wir eine komplette App für diesen gegenwärtigen Markt. Wir beginnen mit demselben Pfad, also dem Pfad /games, aber diesmal müssen wir die eindeutige ID angeben. Und dazu fügen wir hier noch einen weiteren Slash ein, und wir öffnen und schließen geschweifte Klammern, und hier fügen wir den Namen der Eigenschaft ein, die diese eingehende ID repräsentieren soll. und es zu nutzen. Was wir tun werden, ist, unseren zweiten Parameter hinzuzufügen, der, wie Sie wissen, den Handler darstellen wird. Für diese Methode beginnen wir erneut mit der Klammer, doch dieser Abschnitt bietet uns die Gelegenheit, die ID des eingehenden Parameters zu definieren. Also in diesem speziellen Fall erhalten wir eine ID, die exakt dem Namen dieses Parameters entspricht, richtig? Es ist wirklich genau diese ID. Und dann müssen wir erneut festlegen, welche Logik ausgeführt werden muss, wenn eine Anfrage mit genau diesem Muster eingeht, das wir hier definiert haben. Also in diesem Fall beginnen wir damit, unsere Spielesammlung zu durchsuchen, doch diesmal müssen wir das passende Spiel finden. Einfacher Weg, das zu tun, ist die Find-Methode zu verwenden. Wir finden also das Spiel und sagen, dass wir es abrufen möchten, bei dem game.id der als Parameter übergebene ID-Wert entspricht, und das ist wirklich alles, was wir tun müssen. Beachten Sie: PN Net Core ist klug und versteht, dass wir hier einen Parameter ID erhalten, er erwartet ja, dass diese ID Teil der Route hierher kommt. Jetzt starten wir unseren Server, damit wir unseren neuen Endpunkt testen können. Also öffne ich mein Terminal, STRG-J. Dotnet ausführen. Okay, die App läuft nun. Ich schließe das Terminal; Gains dot HTTP. Wir definieren hier einen neuen Endpunkt oder eine neue Anfrage, indem wir sie durch die Raute trennen. Wir müssen drei Rauten setzen, und nun versteht es gut, dass das, was wir hier haben, eine neue Anfrage ist. Diese Anfrage wird im Wesentlichen dieselbe sein wie die vorherige. Ich kopiere es jetzt hier. Und der Unterschied ist, dass ich am Ende ein bestimmtes Spiel anfordern werde. Nehmen wir Spiel Eins, bitte. Klicken wir auf 'Anfrage senden'. Und tatsächlich erhalten wir rechts erneut eine hundertprozentig erfolgreiche Antwort. Okay, App Jason O. Und diesmal sehen wir hier unten Folgendes. Die Antwort, die unserem Spiel Nummer eins entspricht. Großartig. Jetzt wissen wir, wie man die komplette Spieleliste abruft und wie man ein einzelnes Spiel erhält. Aber was, wenn man ein neues Spiel in unsere Sammlung aufnehmen möchte, das einer POST-Anfrage entspricht. Sehen wir uns an, wie das umgesetzt wird. Schließen wir das hier, Strg-J bitte. Ich stoppe den Server mit Strg-C#. Zurück in S. Lass uns ein wenig nach unten scrollen, und erneut definieren wir einen neuen Endpunkt, für unsere API. Jetzt wird es sich um einen POST-Endpunkt handeln, der erneut auf unsere Spielroute abzielt. Bevor wir es tatsächlich implementieren, benötigen wir hier ein brandneues Datentransferobjekt (DTO), das die eingehende Nutzlast für das Spiel repräsentiert, das wir in unserer REST-API erstellen möchten. Also erstellen wir zuerst dieses DTO und danach hierher zurück, um den Endpunkt zu implementieren. Dann öffne ich Strg+Umschalt+E, um den Explorer zu öffnen, und wechsle wieder in den Solution Explorer. Lass uns erneut auf die DTS-Datei klicken, bitte. Es wird noch ein Datensatztyp sein. Und nennen wir diesen hier bitte. Erstelle bitte ein Spiel, TTO. Ich klicke nur auf die Datei, klappe zu. Wie gesagt müssen wir Record nicht nutzen. Es kann auch einfach ein Record sein. Das reicht völlig aus. Wir wechseln erneut zur anderen Syntax mit Klammern, in denen wir festlegen, welche Eigenschaften wir von unserem Client erhalten sollen. In diesem Fall beginnen wir mit dem Namen. Wir fangen nicht mit der ID an, weil die ID gewöhnlich vom Server erzeugt und bereitgestellt wird. Nachdem die Ressource erstellt wurde, erhält man die ID in der Regel nicht direkt vom Client, daher verwenden wir einfach den Namen. Wir verwenden den generischen Spielbegriff. Die C# ML Price Rise Rise, und dann nur unser Veröffentlichungsdatum. Und das ist alles, was wir fürs neue DTO brauchen. Also schließen wir das und kehren zum Cs-Programm zurück, um unseren POST-Endpunkt zu implementieren. Diesmal bauen wir eine App, die POST abbildet. Es gibt viele MAP-Varianten, die wir nutzen können. POST ist ja die richtige Wahl für diesen Fall. Wir fangen mit unserer Spiele-Route an. Und dann legen wir fest, was genau unser neuer, künftiger Handler sein wird, in der Praxis. Jetzt, hier in den Klammern, werden wir genau die Instanz des Create-Game-DTO empfangen, die wir soeben implementiert haben. Also empfangen wir dieses Create-Game-DTO, welches sich auf ein neues Spiel bezieht – nennen wir es so. Lass uns hier unseren Lambda-Ausdruck öffnen, um den Leib festzulegen. Noch einmal: Beachten Sie, wie ASP.NET Core hier wirklich ziemlich klug vorgeht, sodass es den Body erkennt, den wir von unseren Spielen aus senden werden, diese HTTP-Datei, die unser Client ist und die angepasst werden muss. In dieses Objekt hier, das wir 'new name' nennen. Und in diesem Fall, da unsere Spielesammlung im Speicher abgelegt ist, in dieser Liste, von der wir hier wissen, dass wir sie haben, möchten wir einfach nur eine brandneue Instanz von Game-DTO erstellen und dieses Spiel in diese Liste einfügen. Dafür scrollen wir nach unten. Definieren wir unser Spiel. DTO-Spiel neu. Schließen wir das. Und hier geht es darum, die ID zu definieren. Das ist die erste Eigenschaft. Also für die ID verwenden wir einfach 'games.count + 1'. Damit wird die ID für den Namen festgelegt. Wir haben 'new game.name'. Neues Spiel. Neues Spiel, lege den Preis des neuen Spiels fest. Und beim neuen Spiel lege außerdem das Veröffentlichungsdatum fest. Okay, unser neues Spiel ist dort bereit. Jetzt fügen wir es unserer Liste hinzu. Also Spiele, die das Spiel hinzufügen, und zuletzt müssen wir dem Client noch etwas zurückgeben. Und hier gilt die Konvention für eine ordnungsgemäße REST-API darin, eine 201-Antwort zurückzugeben, was bedeutet, dass das Spiel erstellt wurde, und in der Regel möchte man auch die Nutzlast zurückgeben. Von der erstellten Ressource. Jetzt, da wir es auf die folgende Weise tun können, mit dem, was wir gleich sagen werden, ergeben sich Ergebnisse, die eine Route erzeugt haben. Es gibt mehrere Möglichkeiten, dies zu tun. Und für den ersten Parameter hier geben wir den Namen der Route an, die der Client verwenden kann, um auf die gerade erstellte Ressource zuzugreifen. Was ist das für eine Route? Die Route wird hier oben sein, oder? Hier ist sie. Dieser hier, das Kartenkit. Aber wir haben der Route noch keinen Namen gegeben, was optional ist, aber in diesem Fall brauchen wir ihn, damit der POST-Endpunkt diese Route versteht, damit er die richtige URL erzeugt, damit der Client zugreifen kann. Dafür müssen wir hier unter Map Gate einfach einen Aufruf verketten; wir werden einen Aufruf mit Namen verketten, und hier weisen wir diesem Pfad einen Namen zu. In diesem Fall benennen wir ihn in der Tat einfach 'it game'. Und jetzt haben wir eine Möglichkeit, von anderen Endpunkten aus auf diesen Pfad zu verweisen. Also lasse ich es einfach kopieren, das Game zurück ans Ende unseres Map-Posts bringen, und ich werde es hier hinein einfügen, wirklich. Das ist dritter Parameter. 2. Parameter. Es wird die eindeutige Kennung des neu erstellten Spiels sein, die Teil der Get-Spielroute ist. Denk daran, dass die andere Route eine ID erhält. Sie erhält eine ID. Deshalb müssen wir sie als Parameter in MAP-Post eintragen, um die Route abzuschließen. Dafür verwenden wir einen anonymen Typ. Also setzen wir die neue ID gleich der Spiel-ID. Und als letzten Parameter möchten wir die Payload bzw. den Body der Ressource angeben, die gerade erstellt wurde. Das wird also unser Spiel sein. Jetzt ist hier eine gute Praxis darin, denselben String nicht mehrfach in der Anwendung zu hartkodieren; aber im Moment haben wir Get Game und definieren ihn hier im POST-Endpunkt. Außerdem haben wir ihn hier im Get By ID-Endpunkt definiert. Wir können ihn in eine kleine Konstante refaktorisieren, die wir an beiden Stellen verwenden können. Also klicke ich hier auf die Lampe, um Refactorings zu sehen. Und ich wähle das Refactoring "Introduce constant" aus. Ich wähle "Introduce local constant" für GI game aus. Und der Endpunktname wurde der Konstante gegeben, und sie verwendet ihn hier gerade unter diesem Namen. Jetzt geben wir ihr einen besseren Namen. Also drücke ich hier F2, um diese Konstante in Sinnvolles umzubenennen. Nennen wir sie Get Game-Endpunktname. Gib ein. Nun haben wir wirklich einen besseren Namen für die Konstante. Außerdem will ich diese Konstanten oben in der Datei wirklich haben, nicht in der Mitte der Anwendung. Also schneide ich das einfach raus. Ich geh ganz nach oben und definiere es schon vorher. Unser Builder-Objekt. Gleich nach unserer Using-Direktive dort. Also das ist unsere Konstante, und nun können wir dieselbe Konstante nutzen. Ich werde sie einfach kopieren und hier unten für unseren POST-Endpunkt verwenden. Dort. Also haben wir jetzt unseren POST-Endpunkt fertig, und wir können ihn über unsere Gains.http-Datei ausprobieren. Also starten wir unseren Server. Nochmals öffne ich mein Terminal. Äh, wir führen den Start durch. Okay, der Server läuft jetzt. Schließe das hier, kehre zurück zu gains dot TP. Was wir tun möchten, ist wirklich eine brandneue Anfrage einzuleiten. Dann nehmen wir drei Pfund. Lass uns festlegen, dass dies ein Beitrag ist, oder? Also beginnen wir mit dem Beitrag. Die Route bleibt im Wesentlichen dieselbe, daher kopiere ich sie hierher, aber diesmal müssen wir ein paar neue Dinge tun. Zuerst müssen wir wirklich festlegen, welcher Inhaltstyp für diesen Beitrag verwendet wird. In diesem Fall wird nun der Inhaltstyp application/json sein. Und dann müssen wir definieren, was der Body der Anfrage sein wird, um sie zu begleiten. Beachte, hier muss eine leere Zeile stehen, damit es funktioniert. Die neunte Zeile bleibt leer; in Zeile 10 fügen wir den Body ein. Hier verwenden wir korrekte JSON-Syntax. Wir beginnen mit vierteljährlichen Gehaltserhöhungen und liefern danach alle Eigenschaften, die wir im DTO definieren. Erinnere dich daran, dass wir zu Contra Shift E zurück in unseren Game-Store DTS gehen und ein Game-DTO erstellen. Wir haben wirklich festgelegt, dass wir einen Namen angeben, Preis und Veröffentlichungsdatum generieren müssen, daher müssen wir all das als Teil davon liefern. Jason. Payload, also schließe das. Definieren wir unseren Namen. In diesem Fall wird es, sagen wir, Super Mario Bros Wonder sein. Fantastic Game Generate wird ein Plattformspiel sein. Danach haben wir unseren Preis bereits festgelegt. Es wird voraussichtlich 59,99 kosten. Und danach folgt das Veröffentlichungsdatum endgültig, Was der 20.10.2023 sein wird. Okay. Also das ist alles, was wir tun müssen. Jetzt klicken wir auf Anfrage senden, um dieses Spiel in unserer API zu erstellen. Also klicken wir darauf, und auf der rechten Seite können wir sehen, dass der erwartete 201 Created-Status erhalten wurde. Okay? Das bedeutet, dass die Ressource in der RES-API erstellt wurde, und unten hier können wir die Antwort sehen, die wir von dieser Erstellung erhalten haben. Hier drüben ist eine Antwort, die die nagelneue ID der gerade erstellten Ressource enthält. Und nicht nur das: Wir haben diesmal auch das, was man ganz allgemein als Location-Header bezeichnet, dort drüben. Wir erhalten das, weil wir es wirklich verwenden; die Created-At-Route-Methode ist klug genug zu verstehen, wohin der Client gehen kann, um nach der gerade erstellten Ressource zu suchen. Wie dort steht, können wir zu diesem Ort gehen, um die brandneue Ressource abzurufen. Also kannst du fortfahren und das kopieren. Also lass uns das einfach kopieren, und wir können hier zurück zu unserem Get By ID-Bereich wechseln. Wir können einfach diesen gesamten Text durch den anderen String ersetzen. Klicke auf 'Anfrage senden', und nun können wir erneut das Super Mario Bros. Wonder-Spiel abrufen. Prima. Wir haben Endpunkte zum Abrufen und Erstellen von Ressourcen. Jetzt soll ein Endpunkt zum Aktualisieren einer bestehenden Ressource erstellt werden. Also lass uns schließen. Ich werde meinen Server erneut stoppen. Schließe es in Program.cs. Lass uns mal noch ein wenig nach unten scrollen, und hier werden wir unseren brandneuen Endpunkt definieren, der ein PUT-Endpunkt sein wird. Das wird, wie gesagt, unsere Spiele-Route anvisieren, aber das muss auch die ID des zu aktualisierenden Spiels einschließen. Also wenn Sie Spiel Nummer Eins aktualisieren wollten, müssen wir dort die Nummer Eins einschließen und dann den Body der POST-Anforderung angeben. Jetzt, Genau wie wir es mit unserem POST-Endpunkt gemacht haben, müssen wir hier festlegen, wie die Form der Nutzlast aussieht, die wir an unseren PUT-Endpunkt senden sollen. Dafür brauchen wir ein TTO. Also verwenden wir Control Sheet E, um zu unserem Explorer zu gelangen. Wechseln wir zum Solution Explorer. Lass uns mit der rechten Maustaste auf die neue DTS-Datei klicken. Wähle Aufnahme aus und benenne diese hier. Aktualisiere Spiel-DTO. Eingeben. Klicke nun auf Update-Spiel-DTO und falte dieses hier sauber zusammen, bitte. Ich. Lass uns der Richtlinie der anderen DTS folgen, indem wir hier keine Klasse einfügen. Es ist absolut dasselbe. Public Record Update-Spiel, DTO. Lass uns hier noch ganz gezielt auch in die Klammer-Syntax wechseln. Und jetzt hier führen wir die Eigenschaften ein, die wir in diesem Endpunkt erhalten werden. Also erneut: Das wird unser Name und unser Geschlecht sein. Nur unser Dezimalpreis und unser Datum, nämlich das Veröffentlichungsdatum. Und jetzt, da wir unser DT schon haben, gehen wir erneut hinein. Problem C# S, und lasst uns den neuen Endpunkt implementieren. Also für diesen hier werden wir eine App-Map erstellen, hinzufügen. Das Muster wird wieder genau so sein, wie es bei Slash-Spielen festgelegt war. Wir müssen die ID erhalten. Also führen wir hier die ID ein. Und dann definieren wir unseren Lambda-Ausdruck. Lassen Sie mich hier an dieser Stelle den Körper vorbereiten, und damit beginnen wir sogleich damit, alles Notwendige auszuarbeiten, das benötigt wird. Nun müssen wir in diesem Fall zwei Parameter in unseren Lambda-Ausdruck übernehmen. Der erste Parameter wird natürlich die ID sein, also welches Spiel aktualisiert werden soll. Also verwenden wir die ID und den zweiten Parameter. Also gut, die Nutzlast. Die Nutzlast des Spiels, das wir aktualisieren müssen. Also für diesen Fall aktualisieren wir das Spiel-DTO. Aktualisiertes Spiel. Nochmals: ASP.NET Core wird klug sein und auch verstehen, dass erster Parameter direkt aus der Route kommt, während zweiter Parameter aus dem Anfragetkörper kommt. Was wird hier die Logik fürs Update sein? Nun, das Erste, was zu tun ist, ist. Finde das Spiel, das wir aktualisieren müssen. Also machen wir Folgendes. Nehmen wir Bar-Index. Es geht um Spiele. Finde den Index des Spiels, bei dem game.id dem übergebenen ID-Parameter entspricht. Okay, das wird uns also den Index geben. Und basieren wir jetzt auf diesem Index. Wir können dann das Element in unserer Sammlung aktualisieren, das dem Index entspricht. Also, wir werden jetzt wirklich sagen, dass der Spiele-Unterindex dem neuen noch frischen Spielvideo wirklich ganz exakt gleich ist. Das wird als erste Eigenschaft die ID haben, die einfach eine bereitgestellte ID ist. Und dann werden wir das aktualisierte Spiel.Name, das aktualisierte Spiel, das erneut aktualisierte Spiel, den Preis und das Veröffentlichungsdatum des aktualisierten Spiels haben. Okay, das wird wirklich alle Eigenschaften unseres bestehenden Spiels aktualisieren. Und schließlich geben wir gemäß einer guten Konvention in REST-APIs Ergebnisse zurück, die keinen Inhalt enthalten. Und das ist ja so ziemlich alles. So implementierst du diese Version unseres PUT-Endpunkts. Jetzt testen wir es mal. Ich starte meinen Server jetzt erneut. Ich führe im Terminal net run heute aus. Okay. Ich schließe das wieder zu Games. Bei HGTP legen wir hier gleich einen neuen Abschnitt fest. Scrolle jetzt nach unten, ich mache drei Pfund. Das wird wieder an denselben Ort zurückgesetzt. Also werden wir das alles tun. Ich werde das hier einfügen Wie gesagt, müssen wir festlegen, welche ID dem Spiel gehört, das jetzt aktualisiert werden soll, damit wir uns an unsere Ideen erinnern können. Wir können die vollständige Liste der Spiele über unsere erste Anfrage abrufen. Also klicken wir auf Anfrage senden. Hier sind unsere drei Spiele. Wir werden unser Three Fighter 2-Spiel aktualisieren. Vielleicht werden wir die Namen etwas verändern, und den Preis verändern. Also wird dies Spiel Nummer Eins wirklich sein. Um die Dinge einfach zu halten, damit es übersichtlich bleibt. Ich kopiere das hier, Jason. Auch das kopiere ich. Die Idee ist also, dass ich die ID in die Route aufnehme und dort ein Leerzeichen freilasse. Ich füge dort ein, was ich gerade kopiert habe. Lass uns das dort besser abstimmen und dann. Der Hauptunterschied hier ist, dass wir die ID nicht benötigen, da sie Teil der Route ist. Wir können das entfernen; dann müssen wir festlegen, welche Änderungen eingeführt werden. Nun wird es jetzt ein Street Fighter. Topo ist eine Variante des Spiels, und zum Preis ist es im Angebot. So nun entfernen wir sie, damit der Preis neun Komma neunundneunzig ist. Vergiss nicht, hier mal auch festzulegen, was der Inhaltstyp sein wird. Also wird der Inhaltstyp application, JSON, sein, genauso wie wir es mit POST gemacht haben. Also klicken wir jetzt gemeinsam auf 'Anfrage senden'. Und wie erwartet haben wir unsere 204 No Content-Antwort erhalten, was bedeutet, dass dies ein Erfolg war. Eine erfolgreiche Anfrage, und wir können natürlich bestätigen, dass das Spiel durch einfaches erneutes Abfragen desselben Spiels über unsere Abfrage nach der ID aktualisiert wurde. Also werde ich das auf Eins umstellen, dieselbe Abfrage erneut ausführen, und tatsächlich können wir bestätigen, dass das Spiel umbenannt wurde. Es ist ein strenger Kämpfer zu Turbo. Der Preis hat sich geändert. So war das Update gut, ja. Eine Sache ist bei diesem Update oder Endpunkt zu beachten. Also halte ich den Server bitte kurz an. Gehen wir zurück zu Pro Cs. Und es könnte auch mehrere PUT-Anfragen an unsere API geben, die dieselbe Änderung gleichzeitig auslösen. Was hier prinzipiell möglich ist, ist, dass die Spieleliste hier eine statische Liste ist, richtig? Und wenn mehrere Threads gleichzeitig darauf zugreifen und sie verändern, könnte das natürlich zu ernsthaften Dateninkonsistenzen führen. Also für eine Produktionsanwendung ist eine solche Liste keine gute Option. Du willst etwas anderes verwenden, vielleicht ein paralleles Backup oder Ähnliches, das sicher gegen Bedrohungen ist. Wir stehen an einem Wendepunkt und lernen, wie wir unsere beste API erstellen und die Kursstruktur aufbauen. Wir wechseln zu einer ordentlichen Datenbank und entfernen diese Liste vollständig. Stopp. Beachte das, falls du es bitte in die Produktion bringst. Nun werfen wir einen Blick darauf, wie wir unseren letzten Endpunkt implementieren, also unseren Lösch-Endpunkt. Und dazu scrollen wir hier langsam nach unten. Lassen Sie uns einen neuen Abschnitt vor oder nach dem Lauf einfügen. Und das wird ein Löschaufruf an die Spiele sein. Und erneut wird er die ID des zu löschenden Spiels empfangen. Sagen wir, es wird Spiel Nummer eins sein. So würden wir eben den Endpunkt aufrufen. Nun, glücklicherweise benötigt der Lösch-Endpunktsystem keine DTS, da er nur die ID des zu löschenden Spiels empfängt. Er wird keine Payload zurückgeben. Also können wir unseren Endpunkt sofort definieren. Wir werden 'up that map, delete' sagen. Wir definieren hier das Pad. Spiele, bei denen wir DID bitte angeben müssen, Und dann definieren wir unseren Landausdruck, und erhalten die ID. Lass uns Körper definieren. Und da der Zweck dieses Endpunkts darin besteht, das Spiel zu löschen, das der entsprechenden Kennung entspricht, können wir wirklich einfach von 'games dot removal' sprechen. I. An der Stelle, an der sich das Spiel befindet, ist das Spiel mit der ID, die der übergebenen ID entspricht, ein wirklich einfacher Weg, das Spiel zu entfernen. Und dann werden wir erneut mit Ergebnissen antworten, die keinen Inhalt enthalten, was die allgemein gültige Konvention für ordnungsgemäß aufgebaute REST-APIs ist. Beachten Sie bitte, dass es in der API egal ist, ob das Spiel existiert oder nicht; die Konvention für einen Lösch-Endpunkt ist, dass nachdem der Endpunkt die Anfrage empfangen und verarbeitet hat, die Ressource nicht mehr existieren sollte – egal, ob sie vorher existierte oder nicht. Aus diesem Grund prüfen wir nicht einmal, ob das Spiel existiert. Wir entfernen einfach Instanzen des Spiels, deren ID gegeben ist. Okay, also lasst uns diesen neuen Endpunkt testen, indem wir unseren Server erneut starten, dot run. Lass uns über HTTP in unsere Spiele wechseln. Hier fügen wir einen extra Eintrag hinzu. Dreifache Pfunde. Lasst uns bitte löschen. Kopiert und fügt bitte unseren Pfad vom PUT-Endpunkt ein, und lasst uns dabei sagen, dass wir tatsächlich löschen werden, ja? Unser allererstes Spiel, Nummer eins. Zuerst sollten wir bestätigen, was die vollständige Liste der Spiele ist, bevor wir die Löschung durchführen. Klicken wir hier bitte auf unsere erste Anfrage. Wir haben Spiele eins, zwei und drei. Jetzt legen wir los und führen die Löschanfrage aus. Wir senden die Anfrage. Wir erhalten 204 No Content, was bedeutet, dass es ein Erfolg war. Dieses Spiel darf nicht mehr existieren. Wenn du erneut hineingehst, lass uns bei der ersten Abfrage die vollständige Liste der Spiele abrufen. Und wie man sieht, ist Spiel Nummer eins leider verschwunden. Es ist hier nicht mehr verfügbar. Wie gesagt, könnten wir denselben Endpunkt erneut mit Nummer eins aufrufen, auch wenn er nicht existiert. Wir können dieselbe Anfrage erneut senden. Und erneut erhalten wir 204 No Content, weil der Client nicht wissen muss, ob das Spiel vorher bestand oder nicht. Die Richtlinie lautet: Ressource existiert nach dem Endpunkt nicht mehr. Eine Sache, die Sie sich vielleicht fragen, ist, was passiert, wenn wir versuchen, ein Spiel abzurufen, das nicht existiert. Was passiert also, wenn wir unseren ID-Endpunkt hier verwenden, aber die Idee eines Spiels, das einfach nicht da ist. Nun, probieren wir es aus und sehen, was passiert. Starten wir unseren Server erneut. Gehen wir zu den Spielen bei http, und diesmal versuchen wir das Spiel Nummer fünf abzurufen, das überhaupt nicht existiert. Klicken wir auf Anfrage senden. Und wie Sie sehen können, ist ihre Antwort wirklich etwas unerwartet, richtig? Also erhalten wir erneut eine 200er-Antwort, okay? Was schon bedeutet, dass es kein Erfolg ist. Wir können das Spiel nicht finden, und wirklich schlimmer, hier erhalten wir ebenfalls einen neuen Wert, oder wir geben hier einen neuen Wert zurück. Die Risikoleitlinien sagen ausdrücklich, dass, falls die Ressource nicht vorhanden ist, man etwas zurückgibt. Äh, keine Antwort gefunden. Lass uns das richten. Schließen wir das hier. Lass den Server stoppen. Lass uns Cs wieder programmieren. Folgendes tun wir. Wir kehren zu unserer Abfrage nach ID zurück. Lass uns damit beginnen, ihm einen passenden Körper zu geben. Ich öffne hier und schließe vierteljährliche Klammern. Ich bringe es hinein. Unsere vierteljährlichen Klammern sehen so aus. Und dann möchte ich tatsächlich das Endergebnis unserer Spiele registrieren, die den Find-Aufruf auslösen, damit wir überprüfen können, ob wir das Spiel überhaupt finden konnten. Also werden wir sagen, dass unser Spiel dem entspricht, was Find-Aufrufe bewirken; lassen wir das kurz festlegen, und dann. Was wir tun können, ist Folgendes, Da unsere Spielvariable hier wirklich dauerhaft erneuerbar sein wird. Beachten Sie hier bitte das Fragezeichen. Das bedeutet, dass es wirklich durchaus neu sein könnte; also sagen wir, dass wir zurückgeben, falls das Spiel neu ist. Falls es neu ist, geben wir tatsächlich Ergebnisse zurück, die nicht gefunden werden, was die logisch erwartete Antwort ist, wenn die Ressource nicht gefunden werden kann. Und ansonsten beabsichtigen wir wirklich einfach, Ergebnisse zurückzugeben, die in Ordnung sind, einschließlich unseres Spielobjekts dort. Und das sollte reichen, um die richtige Antwort zu geben, je nachdem, ob das Spiel existiert. Also probieren wir das jetzt mal aus. Lass uns unseren Server neu starten. Lass uns Spiele über HTTP aufrufen, und erneut versuchen, Spiel Nummer fünf abzurufen. Mal sehen, was passiert. Senden wir eine Anfrage, und tatsächlich erhalten wir jetzt den 404 Not Found. Es gibt hier keine Antwort, und das zeigt dem Client eindeutig darauf hin, dass die Ressource wirklich nicht vorhanden ist. Nun sollten wir auch unseren PUT-Endpunkt ähnlich behandeln, oder? Denn auch das wird versuchen, diese Ressource zu lokalisieren. Also scrollen wir hier nach unten zu meinem PUT-Endpunkt. Und hier, direkt nachdem wir den Index des Spiels gefunden haben, werden wir sagen, dass der Index -1 ist, falls diese Bedingung zutrifft. Was bedeutet, dass wir den Index des angefragten Spiels in diesem Zusammenhang nicht finden konnten. Wir geben einfach Ergebnisse zurück, die in dieser Situation nicht gefunden wurden. Jetzt ist der Fakt, dass wir 'nicht gefunden' zurückgeben, wenn wir die Ressource nicht finden können, eine polemische Aussage, denn manche sagen, man solle stattdessen ganz einfach die Ressource erstellen, falls sie nicht gefunden wird, um die Anforderungen einer POST-Anfrage zu erfüllen. Jetzt gibt es keine klare Antwort dazu. Und im Rahmen dieses Kurses wähle ich einfach den vorhandenen Noten-Ansatz. Also testen wir das kurz. Wir prüfen, ob es klappt, wie erwartet. Also starten wir unseren Server. Wir gehen zum PUT-Endpunkt. Wir versuchen es erneut; Spiel Nummer fünf existiert nicht. Gleiche Anfrage. Und wie vermutet, erhalten wir endlich eine Nicht gefunden-Antwort. Nun, eine Sache, die Sie jetzt beunruhigt, ist, wie viel Code wir in dieser CS-Datei des Programms haben. Denn wenn wir so weitermachen, wird es immer schwieriger, Dinge in der Datei zu finden und schnell Änderungen vorzunehmen, oder nicht wahr? Das ist also wirklich keine gute Praxis, ja, klar. Also können wir alle diese Endpunkte, die wir bisher im C#-Programm deklariert haben, einfach in eine brandneue Klasse verschieben, die speziell dazu entworfen ist, die Endpunkte zu definieren. Und damit wird uns außerdem eine besonders leicht verständliche, äußerst bequeme Methode ermöglichen, alle Endpunkte auf einmal zuverlässig zuzuordnen. Dazu gehen wir zurück in den Lösungs-Explorer. Also Kontrast Shift-E. Hier sind wir im Social Explorer, Und legen wir zuerst einen neuen Ordner für unsere Endpoints an. Klicken wir mit der rechten Maustaste auf Game Store API. Wir erstellen einen neuen Ordner. Wir nennen ihn Endpoints. Dann erstellen wir in diesem Ordner eine Klasse. Also klicken wir erneut mit der rechten Maustaste auf Endpoints. Eine Datei wird eine Klasse sein. Benennen wir Games Endpoints. Geh rein. Lass uns zu den Endpunkten des Spiels gehen, CS jetzt. Jetzt lösch ich unnötige Using. Und wie ich bereits gesagt habe, wird der Zweck dieser Klasse darin bestehen, alle unsere API-Endpunkte zu enthalten. Und das tun wir, indem wir verwenden, was wir als Erweiterungsmethoden kennen. Erweiterungsmethoden gehören zu statischen Klassen, welche wir wirklich kennen. Bevor wir hier unsere Erweiterungsmethode definieren, beginnen wir damit, durch unsere Spielesammlung zu stöbern. Also wählen wir hier die vollständige Sammlung aller Spiele aus – die umfangreichste. Rechtsklicken wir. Wir schneiden das hier heraus und bringen es zu den Spiele-Endpunkten, CS. Fügen wir es direkt genau hier in unsere neue Klasse ein. Lass uns das hier so noch etwas besser formatieren. Lass uns das Game-DTO behandeln. Lass uns das so machen, damit wir unsere Spielstore-API importieren können. DTO NextSpace. Und da wir jetzt soweit sind In eine passende statische Klasse. Wir müssen das richtig definieren. Also wird das hier eine private statische Liste von Spiel-DTOs, die wir Spiele nennen. Außerdem, da wir nach dem Erstellen unserer Games-Endpunkt-Klasse keinen neuen Wert mehr in dieses Games-Objekt zuweisen werden, ist hier eine gute Konvention, dieses Objekt als readonly zu definieren. Also setzen wir readonly, wodurch die Definition unserer Liste hiermit abgeschlossen ist. Wenn wir nun wieder zu ES zurückkehren, ist als Nächstes auch die Definition unserer GI-Endpunkt-Namenskonstante dran. Lass uns das beseitigen und es oben in unseren Gains-Endpunkt als eine Konstante aufnehmen. Jetzt ist es Zeit, unsere Erweiterungsmethode zu festlegen. Also scrollen wir nach unten. Gleich nach der Liste definieren wir die Methode. Es wird eine statische Methode sein; Erweiterungsmethoden bleiben statisch. Wir geben doch void zurück. Nennen wir dieses hier. Spiele-Endpunkte abbilden. Da diese eine Methode alle Endpunkte abbilden wird, müssen wir definieren, was genau wir erweitern wollen. Das bedeutet, dass wir dem Objekt, das hier übergeben wird, neue Methoden hinzufügen, um ein Objekt zu erweitern. Wir fangen damit an, zu definieren, indem wir dieses Schlüsselwort verwenden, und legen dann fest, was erweitert werden soll. Das, was wir hier erweitern wollen, führt zurück zu Program.cs. Wir möchten hier das App-Objekt erweitern, das wirklich vom Typ Webanwendung ist. Dafür gehen wir hier zurück und definieren die Webanwendung. Rauf, dann legen wir den Körper der Methode fest, bitte. Dafür. Im Grunde müssen wir nur die Definition aller unserer Endpunkte einbringen. Also lasse ich mir hier einfach alles bis zum Löschpunkt greifen und mit der rechten Maustaste klicken und Ausschneiden. Aber zurück zum Games-Endpunkt, fügen wir einfach ein, was wir gerade kopiert haben. Und jetzt mal Wir tun dasselbe wie früher, aber diesmal im Zusammenhang mit dieser neuen Erweiterungsmethode. Beachte, dass es im Wesentlichen derselbe Code ist. Nichts ändert sich. Wir fügen weiterhin alle Methoden zur Webanwendung hinzu. Aber jetzt liegt diese Methode in dieser Map bei den Spiel-Endpunkten. Und damit können wir wieder zum Programm Cs zurückkehren, und hier sehen wir jetzt wirklich diesen leeren Raum; wir können nun eindeutig 'up dot map' sagen. Spiele-Endpunkte, korrigiere Groß- und Kleinschreibung, und so machen wir es, bitte, ja. Lass Strg-Punkt verwenden. Um unseren neuen Spiele-Shop zu importieren, die API, diesen Endpunkt Aspace. Räumen wir dort auch kurz diesen Bereich auf. Und jetzt ist dies der vollständige Inhalt unseres Programms, dieser CS-Kurs, wie man sieht, wird es wirklich ganz viel leichter zu warten sein. Anstatt hier Unmengen Zeilen Code zu haben. Nun gehen wir hier wieder zu den Spiel-Endpunkten zurück, und noch etwas, das wir tun können, ist auch. Vereinfache ein wenig die Art und Weise, wie wir unsere Endpunkte definieren, denn wie du sehen kannst, definieren wir unsere Gains-Route mehrfach, richtig? Wir definieren sie hier und dort im GET-Endpunkt, und wirklich in jedem einzelnen Endpunkt, und das ist fehleranfällig. Stattdessen können wir das tun, was man als sogenannte Route-Gruppe bezeichnet. Das wird den Basisteil des Ausdrucks eindeutig definieren, und dann können wir jeden einzelnen der Endpunkte in diese Gruppe sicher und zuverlässig einfügen. Dazu öffnen wir hier eine neue Zeile, und wir sagen hier einfach wirklich, sehr deutlich, bitte, noch, bar group equals up that map group here. Wir führen nun das eigentliche Pad hier direkt ein, das Slash Games sein wird, wie vorgesehen, aktuell. Lass mich dieses hier kopieren. Wir legen es hierher, ganz bequem. So das hier ist unsere Gruppe. Und jetzt, statt Map-get und Map-post auf dem ursprünglichen App-Objekt aufzurufen, können wir sie nun am Gruppen-Objekt aufrufen. Also lass mich die Gruppe kopieren und lass uns alle unsere App-Aufrufe vollständig durch Gruppe ersetzen. Also jetzt Gruppen-Map, get Gruppen-Map, post, bitte. Gruppen-Map setzen und auch Gruppen-Map, sofort löschen, bitte. Nun ist natürlich wirklich der nächste Punkt, dass wir nicht mehr für jeden einzelnen Endpunkt Gains definieren müssen, weil sie in der Praxis von der Gruppe vererbt werden. Also können wir das jetzt auf einfach nur '/' reduzieren, was immer noch zum Endpunkt führt. Es muss unter Slash-Gains definiert werden, aber der Endpunkt selbst muss das nicht definieren. Das wird aus der Route-Gruppe entnommen, in der Regel. Gleiches gilt, auch hier. Wir können MapKit anhand der ID verwenden, falls nötig. Dieses hier können wir eventuell entfernen. Vielleicht ist es so: Map-Post kann so sein; Map-Put könnte so sein; und Map-Delete könnte auch so sein. Ein wichtiger Aspekt der REST-API-Entwicklung ist die Prüfung der Eingaben an unseren Endpunkten. Um zu sehen, warum das wichtig ist. Mal sehen, was passiert, wenn wir hier unsere POST-Anfrage ändern, damit. Wir geben keinen Namen für das Spiel an, oder? Also lasse ich das hier komplett weg. Jetzt hat das Spiel keinen Namen, und selbst damit klicke ich auf Senden der Anfrage. Mal sehen, was passiert. Okay, so wurde die Ressource erstellt. Wir haben hier eine 201 erstellt. Allerdings haben wir jetzt wieder was ohne Namen. Als Teil unserer API-Ressourcen. Also sind das inkonsistente Daten. Und das ist etwas, das vielleicht in Zukunft zu Problemen führt. Schauen wir uns jetzt an, wie wir das verhindern können. Lass uns das hier schließen, und ich werde jetzt mal meinen Server stoppen. Gehen wir zu unseren Endpunkten und Gains-Endpunkten, und suchen wir hier den POST-Endpunkt, um zu sehen, was wir dagegen tun können. Eine Sache, die wir tun könnten, ist zum Beispiel, wenn wir dieses neue Spiel mit einem Create-Game-DTO erhalten. Nun können wir hier vorgehen und die Eigenschaften validieren, bevor irgendeine der weiteren Logik fortgesetzt wird, richtig? Also hier in meiner Zeile 49 könnten wir Folgendes tun: Wenn der String neu oder leer ist, dann erzeugen wir einen neuen Game.Name; wir könnten außerdem so etwas wie 'return results.Request' verwenden, und wir könnten hier sogar eine Meldung bereitstellen, möglicherweise eine detaillierte Meldung, oder? Also muss ein Name da sein, sonst klappt der Rest der Logik nicht, wenn der Name fehlt. Aber natürlich, selbst wenn wir das tun, müssen wir auch jedes Merkmal unseres DTO prüfen, richtig? Sie ermitteln den Preis. Alle übrigen Eigenschaften dienen und zwar dazu, sicherzustellen, dass wir wirklich auch alles validieren. Das würde klappen, aber diese Methode wird sehr ausladend. Und wenn wir das wirklich für jeden Endpunkt tun, führt das zu vielen Validierungszeilen. Stattdessen entferne ich diese Zeilen sofort, bitte. Was wir tun können, ist, unser DTO so zu ändern, dass die Eigenschaften Validierungsregeln haben. Welche Validierungsregeln gelten für sie, bitte? Hier drücke ich F12, um zur Definition unseres CreateGameDTO zu gelangen. CreateGameDTO. Und was wir tun können, ist zu definieren, was als Datenanmerkungen bekannt ist, bei den Eigenschaften. So zum Beispiel gilt für unseren Namen, dass der Name erforderlich ist. Und dazu benutze ich Strg. Punkt und wähle das System, das Component Model und den DataAnnotations-Namensraum. Dieses Attribut sorgt dafür. Schon bevor das DTO-Objekt in unseren Endpunkt aufgenommen wird, validiert ASP.NET Core, dass der Name wirklich einen Wert hat, ansonsten liefert es von selbst einen Fehler zurück. Jetzt reicht es nicht aus, dieses Attribut hier in unsere DTO-Eigenschaft einzufügen, damit die Eingabevalidierung erfolgt. Sie müssen außerdem die Validierungsdienste aktivieren oder registrieren, damit ASP.NET Core sie dafür verwenden kann. Gehen wir zurück zu unserem Explorer Contra E. Gehen wir in das Programm, das zur CS-Datei gehört. Und hier können wir unser Builder-Objekt verwenden, um zusätzliche Dienste zu registrieren, die wir als Teil unserer Anwendung aktivieren möchten. Dafür füge ich hier einfach ein paar kurze Zeilen hinzu; Folgendes tun wir. Wir sagen: Builder, diese Dienste – das ist die Sammlung aller Dienste, die wir auch mit der Anwendung registrieren möchten. Und wir fügen Validierung hinzu. Damit werden die Validierungsdienste für jeden einzelnen Endpunkt unserer API verfügbar sein. Also, wenn wir die Anwendung noch einmal ausführen, machen wir einfach den zehnten Durchlauf. Okay? Gehen wir also wieder zu Games bei H C#, TP, und versuchen erneut diese POST-Anfrage, die keinen Namen hat, richtig? Also senden wir die Anfrage, und dieses Mal. Wie vermutet, erhalten wir nun sofort vollautomatisch dort eine schlechte Anfrage, und hier unten sieht man eine sehr schöne Fehlerauskunft, die deutlich sagt, dass ein oder mehrere Validierungsfehler tatsächlich aufgetreten sind, und sie zeigt, welches Feld den Fehler verursacht hat. In diesem Fall handelt es sich um die Name-Eigenschaft, und hier steht, dass das Namensfeld erforderlich ist. Wie Sie sehen, ist es wirklich leicht umzusetzen, und es war überhaupt nicht nötig, die Logik des Endpunkts zu ändern. Es hat nur das Attribut angeschaut, das wir im Game-DTO hinzugefügt haben. Jetzt stoppe ich meinen Server, und wir sollten das noch ein wenig weiter verbessern, indem wir prüfen, dass nicht nur der Name erforderlich ist, sondern auch. Wir wollen nicht zulassen, dass Spielnamen zu extrem langen Zeichenketten werden. Zum Beispiel können wir hier die Zeichenlänge festlegen und hier den Wert der maximalen Länge für diese Zeichenkette sorgfältig angeben. Nehmen wir also an, dass es nur fünfzig Zeichen sind. So wäre der längstmögliche Name eines unserer Spiele, definitiv. Also damit: Wenn wir die Softwareanwendung erneut ausführen, machen wir den Net Run. Lass uns bei HGTP wieder zu den Spielwelten zurückkehren. Aber diesmal entferne ich das wirklich einfach. Das funktioniert gut. Ich werde diesen Namen mehrmals hintereinander kopieren und einfügen. Also sollten diese wirklich länger als 50 Zeichen sein. Und heute werde ich zurückkehren. Los geht's: Ich werde versuchen, eine Anfrage zu senden, und wie erwartet erhalten wir erneut eine fehlerhafte Anfrage, doch diesmal nicht, weil uns der Name fehlt, sondern wie Sie hier deutlich sehen können, muss der Feldname eine Zeichenkette mit einer Höchstlänge von 50 Zeichen haben. So lässt sich die Länge Ihrer Zeichenfolgen überprüfen. Lass uns das hier schließen. Entferne diese Zusatz-Strings. Server stoppen. Dann haben wir das für unsere Namenseigenschaft erledigt. Vielleicht möchten wir dasselbe auch für unseren Spiel-Generator tun. Richtig? Dann kopiere ich das hierher. Für unsere Generierung brauchen wir kürzere Zeichenketten. Sagen wir also 20 Zeichen. Und dann legen wir auch unseren Preis fest. Was den Preis betrifft, ist es so, dass wir sicherstellen möchten, dass unser Preis eine positive Zahl ist, und vielleicht möchten wir auch wirklich keine Preise von mehr als Hundert Dollar zulassen. Um das Ganze zu erläutern, können wir hierfür das Bereichs-Attribut verwenden. Also werde ich nunmehr das Wort Range nennen und es dann benutzen. Von eins bis hundert. Also, jetzt, falls wir die Anwendung erneut ausführen, bringen wir dies wieder zu Games zurück, H C#, TP. Dieses Mal versuchen wir zudem, ein Spiel mit einem Preis von fünfhundertneunundfünfzig Dollar einzuführen. Also senden wir nun eine Anfrage, und wie man deutlich sehen kann, erhalten wir erneut eine fehlerhafte Anfrage, und diesmal steht hier klar, dass das Feld Preis zwischen eins und hundert liegen muss. Ein solcher Preis ist nicht gestattet. Ich. Okay, lass uns das hier schließen. Wir stoppen den Server, und an diesem Punkt erledigt das unser Create-Game-DTO; dasselbe sollten wir auch für das Update-Game-DTO tun, oder? Wir möchten außerdem Validierungen für PUT-Anfragen einführen. Für diesen Fall werde ich jetzt einfach diese Eigenschaften kopieren, um es etwas schneller zu machen, damit wir später rascher weiterarbeiten können. Also kopieren. Lass uns C# Shift E ausführen, das Game-DTO aktualisieren, und lass uns das, was ich gerade kopiert habe, hier einfügen. Hier ist dieselbe Reihe von Eigenschaften. Am Ende lass uns C#-Kontrollen hier verwenden, um System-C# vorzustellen und Modelldatennotationen zu vergleichen. Und jetzt sollten wir denselben Validierungsumfang haben. Bei unserem PUT-Endpunkt. Also probieren wir das jetzt sehr schnell aus. Dann, dann lauf. Lass uns in unsere Spiele bei HTP gehen. Lass uns dieses Mal in unsere PUT-Anfrage gehen. Das wird Spiel Nummer eins sein, und dieses Mal versuchen wir es einfach. Was passiert, wenn wir ein leeres General-Feld haben, richtig? Also, ein leeres General-Feld: Wir klicken auf Senden der Anfrage. Und sicher genug, wieder einmal haben wir eine schlechte Anfrage erhalten, und diesmal liegt es daran, dass das General-Feld erforderlich ist. Sie können auch andere Eigenschaften prüfen. Für unsere PUT-Anfrage denke ich wirklich, du siehst, wie wirklich einfach es ist, Eingabevalidierung durch Datenanmerkungen und die Validierungsdienste von ASP.NET Core zu ermöglichen. Jetzt möchten wir der REST-API eine Datenbankanbindung geben, damit alle Daten nach der Replikation gespeichert bleiben. Wenn eine Anfrage zum Anlegen eines Spiels in unserer API eingeht, möchten wir das Spiel in der Datenbank speichern. Und wenn der Client eine Auflistung von Spielen anfordert, möchten wir diese Auflistung aus der Datenbank abfragen. Aber es gibt ein Problem. Die Datenbank spricht nicht die gleiche Sprache wie deine C# .NET Core API. Ihre API ist in C# (C-Sharp) geschrieben, aber Ihr relationaler Datenbankserver versteht nur SQL bzw. die SQL-Sprache. Das bedeutet, um die Anfrage zum Abrufen von Spielen zu erfüllen, muss Ihr C#-Code zusammen mit dem API-Code die API-Anfrage in eine sorgfältig erstellte SQL-Abfrage übersetzen und diese Abfrage dann an den Datenbankserver senden. Der Datenbankserver führt die Abfrage aus; Ihr C#-C#-R-Code muss alle ergebenden Rollen zurücklesen und sie in API-Antwort übersetzen. Das verursacht noch einige Probleme. Als C#-Entwickler müssen Sie jetzt eine neue SQL-Sprache lernen, um die nötigen Abfragen zu erstellen, und sie gut beherrschen, damit Sie wirklich gute Leistung erzielen. Sie müssen viel zusätzlichen Datenzugriffscode schreiben, dessen einziger Zweck darin besteht, Dinge von C# nach SQL und umgekehrt zu übersetzen, und mit unerwarteten Fehlern umgehen. Beim Sprechen über Fehler ist dieser Ansatz fehleranfällig; es ist leicht, Fehler zu machen, wenn Dinge seitenweise übertragen. Und Sie müssen Ihre Anfallmodelle manuell mit den passenden Tabellen der Datenbank abgleichen; das ist nicht einfach. Hier können optimierte relationale Mapping-Techniken oder ORM viel bewirken. Aber was ist OM? Nun, zurück zu unserem Spotify-Beispiel: Stellen Sie sich vor, Ihre Anwendung wurde nach einem objektorientierten Paradigma erstellt und enthält daher Objekte zur Darstellung von Songs, Künstlern und Playlists. Und wenn Sie mit einem relationalen Datenbankserver arbeiten, besteht eine gute Chance, dass Ihre Datenbank entsprechende Tabellen für jedes dieser Objekte hat. Jetzt muss kein eigener Code mehr geschrieben werden, um Objekte auf Tabellen abzubilden. Wenn Daten an die Datenbank gesendet oder von ihr empfangen werden müssen, richte eine Zuordnung zwischen ihnen ein, damit dein Programm weiter mit Objekten arbeiten kann, während ein ORM die Umwandlung von Objekten in Tabellen und zurück übernimmt. Im Wesentlichen ist Objekt-Relationales Mapping eine Technik, Daten zwischen einer relationalen Datenbank und einem objektorientierten Programm zu übertragen. Und wie Sie sich vorstellen können, bringt es vielen Entwicklern Vorteile. Und glücklicherweise enthält ASP.NET Core ein großartiges ORM-Framework namens Entity Framework Core. Also, was ist Entity Framework Core? Es ist ein leichtgewichtiges, erweiterbares Open-Source- und plattformübergreifendes Objekt-Relationaler Mapper (ORM). Entity Framework Core wird zwischen Ihrer REST-API und Ihrem Datenbankserver sitzen. Neben der Abbildung Ihrer .NET-Objekte auf Datenbanktabellen übersetzt es Ihren Datenzugriffs-Code in SQL-Anweisungen, die der Datenbankserver verstehen kann, und es übersetzt außerdem alle aus der Datenbank resultierenden Daten in Objekte, die Ihre API mühelos verwalten kann. Die Nutzung des Anti-Framework-Kerns in Ihren Dan-Anwendungen bringt Vorteile. Sie müssen doch keine neue Sprache lernen. Sie können alle Datenzugriffsaufgaben mit Ihrer vertrauten C#-Sprache durchführen. Der für den Datenzugriff notwendige Code ist minimal. Weil jedes DD-Framework den Großteil davon übernimmt. In der Tat können Sie LINQ verwenden, um die meisten Abfragen Ihrer Datenbank auszuführen. Es gibt Werkzeuge, die deine C#-Modelle mit der DB synchron halten, damit du das nicht mehr manuell tun musst. Das Framework kann Änderungen verfolgen. Zur Laufzeit stehen deine C#-Objekte, damit klar ist, welche Änderungen an DB gesendet werden müssen, wenn Zeit ist, die Daten zu speichern. Schauen wir uns nun an, wie man mit antide Framework Core der API unseres Spielstores eine Datenbankunterstützung hinzufügt. Der erste Schritt bei der Integration unserer S Vnet Core-API in eine relationale Datenbank besteht darin, unser Datenmodell genau zu definieren. Das Datenmodell wird sämtliche Klassen vollständig umfassen. die wir nutzen werden, um Objekte zu machen, die gespeichert werden müssen. In unseren Datenbanktabellen. Also fangen wir damit an, unseren Lösungsexplorer zu öffnen. Vielleicht klicken wir dann rechts auf den neuen Ordner der Game Store API. Und lassen wir es Modelle nennen. Klicken wir jetzt im Modellordner mit der rechten Maustaste. Eine neue Datei. Das wird wirklich eine Klasse sein, und nennen wir diese hier 'game'. Großartig. Öffne unser Spiel. Mach C#-Datei. Lösche unnötiges Using. Und jetzt stellen wir mal alle Eigenschaften vor. Unser Gangmodell. Der erste wird unsere ID sein, also definieren wir bitte mal eine öffentliche ID mit einer Sammelantwort. Dann definieren wir jetzt bitte unseren öffentlichen String-Namen mal. Was übrigens dazu führt, diese Warnung hier anzuzeigen, weil der Compiler darauf besteht, dass wir sicherstellen, dass die Namenseigenschaft nach dem Erzeugen einer Instanz der Game-Klasse I zu jedem Zeitpunkt immer einen Wert besitzt. Eine Möglichkeit, dies zu lösen, besteht auch darin, die Namenseigenschaft möglicherweise mit leerem String zu initialisieren. Eine andere Lösung besteht darin, die Namenseigenschaft kennbar zu machen. Wenn du das tust, ist es ein kenntbares Objekt, beim Erzeugen des Objekts muss kein Wert festgelegt werden, wir möchten jedoch einen Wert haben. In der Namenseigenschaft eines Spiels ergibt es keinen Sinn, ein Spiel ohne Namen zu haben. Was wir tun können, ist tatsächlich das in diesem ganz besonderen Zusammenhang erforderliche Schlüsselwort in der Praxis zu verwenden, damit der Compiler von uns verlangt, dass wir einen Wert für den Namen angeben. Nun, als Nächstes müssen wir unser Spielkonzept festlegen. Doch zu diesem Zeitpunkt werden wir uns nicht mehr darauf beziehen. Als einfachen String degenerieren. Wir möchten in einer Datenbank eine eigene Tabelle für Generierungen haben, und deshalb müssen wir Degenerieren als eine weitere Klasse definieren, die Teil unseres Datenmodells sein muss. Also gehen wir wieder in den Solution Explorer. Klicken wir erneut auf Modelle, neue Datei, Klasse. Äh, tippe hier Januar ein, bitte. Öffnen wir jetzt Januar, bitte, zusammen. Räumen wir das hier im Raum auf. Und unsere Implementierung wird eine sehr einfache Klasse sein, die zudem über eine öffentliche ID vom Typ Integer verfügen wird und zusätzlich über einen öffentlichen, erforderlichen String-Name verfügt, und zwar eben jeweils mit einem Getter und einem Setter. Jetzt können wir wieder ins Spiel gehen. Und wir können hier noch etwas hinzufügen. Unser öffentliches Repository; daraus folgt tatsächlich, dass dies eine zusammengesetzte Eigenschaft sein wird. des Spielmodells. Jetzt erneut erhalten wir wirklich die Warnung des Compilers, der verlangt, dass wir hier einen Wert für unsere January-Eigenschaft setzen, weil der Typ im Moment wirklich nicht machbar ist. Und in diesem Fall werden wir diesen Typ wirklich durch das Hinzufügen des Fragezeichens machbar machen, denn wie du im Verlauf des Kurses sehen wirst. Es wird Situationen geben, in denen wir für diese zusammengesetzte allgemeine Eigenschaft keinen Wert festlegen möchten. Dies wird der Fall sein, wenn wir uns nur mit der Idee des Generators befassen müssen, aber nicht mit dem Generator-Objekt, wenn wir nach unseren Spielen suchen möchten. Reicht es, Navigations-Eigenschaft in unserem Spielmodell zu haben, die in die Generierung geht. Es wird ausreichend sein, damit das Entity Framework verstehen kann, dass es ein Fremdschlüssel sein muss. Von unserer Spieltabelle in die Allgemeintabelle. Allerdings ist es aus guter Praxis deutlich besser, ... Hier definieren wir deutlich ein weiteres Attribut, das diesen Fremdschlüssel darstellt. Also hier werden wir nun unser öffentliches Attribut definieren. Damit weiß der Kern jedes D-Frameworks mit Sicherheit Bescheid. Wir möchten jedoch diesen Fremdschlüssel von Game zu Generate haben, aber er gibt uns die Möglichkeit, in vielen Szenarien direkt mit der Generate-ID arbeiten zu können, ohne die gesamte Generate-Eigenschaft laden zu müssen. Wenn wir Spiele aus der Datenbank abrufen möchten, was wesentlich schneller sein wird, werden wir sehen, wie wir diese beiden Eigenschaften im Verlauf der Implementierung unserer Endpunkte austauschbar verwenden, und zwar Schritt für Schritt. Auch, weil die generierte ID nicht bekannt ist, oder? Also ist das nicht bekannt. Es bedeutet, dass die Beziehung hier Es wird ausdrücklich verlangen, dass einem Spiel-Datensatz eine generierte ID zugeordnet wird; diese Zuordnung ist damit nicht optional. Sie ist erforderlich, wie es sein sollte. Nun vervollständigen wir unser Spielmodell, indem wir unseren öffentlichen Dezimalpreis einführen und unser öffentliches Veröffentlichungsdatum (nur Datum). Und damit ist unser Datenmodell vollständig. Bereit, Anti-Different-Work-Core in unsere API einzuführen. Um Antide-Framework-Kern in unsere Vnet-Core-API zu integrieren, nutzen wir ein neues Bibliothekenset, das standardmäßig nicht mit Vnet-Core geliefert wird. Diese Art Bibliotheken sind verteilt. Pakete, die als NuGet-Pakete bekannt sind. Und der Ort, an dem man sie findet, ist diese Seite no.org. Dies ist das größte Repository für No-Pakete, und du solltest doch in der Lage sein, jedes Nugget-Paket zu finden, das du jemals brauchst, indem du es hier einfach suchst. NDE Framework Core unterstützt mehrere DB-Anbieter. Aber im Rahmen dieses Kurses verwenden wir SQLite, weil es sehr leichtgewichtig ist und sich gut damit arbeiten lässt. Wenn du dabei bist zu lernen, wie man mit Fin Core arbeitet, um den ESQ Light-Datenbankanbieter für .NET Framework Core vorzustellen, ist das Paket, das du verwenden möchtest, dieses hier, namens Microsoft.Data.Sqlite. Hier können Sie auf Suche klicken, und es werden alle Pakete gefunden, die dem Suchbegriff entsprechen. In der Regel ist das allererste das, was Sie verwenden möchten. Microsoft Entity Framework Code Dot Escalate. Klicken Sie bitte darauf. Auf dieser Seite finden Sie viele Details zu diesem Paket, einschließlich der neuesten Versionen. Auch der genaue .NET C#-String zum Paket installieren. Wenn Sie .NET C#-CLI nutzen möchten, Nun ist dies eine von mehreren Möglichkeiten, es zu tun, doch nochmals: Da wir das C#-R-Entwicklerkit verwenden, gibt es einen einfacheren Weg, es direkt aus VS Code heraus zu erledigen. Also kehren wir zu VS Code zurück und öffnen den Solution Explorer. Wir klicken mit der rechten Maustaste auf unser King Store a P-Projekt. Wir wählen NuGet-Paket hinzufügen und suchen nach Microsoft Antide Defined Work Code Esq Light Heat. Gib ein Unser Paket ist hier der allererste Eintrag. Darauf klicken. Und hier werden Sie aufgefordert, die Version zu wählen, die Sie für Ihre Anwendung verwenden möchten. Da unsere Anwendung auf .NET 10 abzielt, wählen wir die neueste stabile Version. Für .NET 10, das hier gemeint ist, Version 10.0.0.1. Also klicken wir auf diese hier, und dieses Paket ist installiert worden. Nun gibt es keinen klaren visuellen Hinweis darauf, dass das Paket installiert werden kann. Aber öffnen wir hier unsere Abhängigkeiten und dort unseren Paket-Knoten, sehen Sie, dass der .NET Framework-Code hier erscheint, was bedeutet, dass das Paket installiert werden kann. Und außerdem, wenn Sie auf das Projekt selbst klicken, sehen Sie auf der rechten Seite, dass wir wieder zu unserem C#-Profil zurückkehren, und äh. Wir finden diesen Knoten, einen Paketverweis, der die Installation des Microsoft Entity Framework Core-SQL-Paket darstellt. Ein Core-SQL-Paket mit der Version zehn Punkt null Punkt eins. Super. Wir haben jetzt Unterstützung von Entity Framework Core in unserer API. Wollen wir mit dem Erstellen beginnen? Die Objekte, die nötig sind, um unser Modell in SQLite-Tabellen abzubilden. Also schließen wir das hier. Gehen wir mal zurück in den Lösungs-Explorer. Klicke mit der rechten Maustaste auf die Game Store-API. Ordner neu erstellen. die wir Data bezeichnen Und Inside Data. Rechtsklick und erstelle eine neue Datei, die eine Klasse ist. Und wir wollen es in diesem Game Store-Kontext benennen. Drücke Enter und öffne es bitte gleich in unserem leistungsfähigen Editor hier. Using-Direktiven entfernen. Und der Zweck dieser GameStore-Kontextklasse besteht darin, wirklich dein DV-Kontext zu sein. Welches im Kontext des Anti-Framework-Kerns eine Sitzung zwischen Ihrer API und der Datenbank repräsentiert. Und kann sowohl zum Abfragen verwendet werden. Und speichert Instanzen der Entitäten in der Datenbank. Man kann den DB-Kontext durchaus als Verbindung von Unit-of-Work-Mustern und Repository-Mustern sehen. Nun, um diese Game-Store-Kontextklasse in einen DB-Kontext zu verwandeln, müssen wir sie aus der DB-Kontextklasse ableiten, die mit dem .NET Framework Core geliefert wird. Verwende ich C# Strg+Punkt, damit wir den Microsoft .NET Framework Core-Namensraum einführen können. Du musst deinem DB-Kontext auch sagen, wie er sich mit deiner Datenbank verbinden soll, und das tust du, indem du die sogenannten DB-Kontext-Optionen übergibst. Und das tust du, indem du die DB-Kontext-Optionen übergibst, die man so nennt. Hier werden wir einen Primärkonstruktor einführen, der DB-Kontext-Optionen des Typs Game Store Context erhält. Und nennen wir den Parameter einfach Optionen. Jetzt senden wir dies in die nächste Zeile, und wir übergeben das Options-Objekt an den Basiskonstruktor. Mehrere Parameter, darunter Verbindungsstrings, werden im Rahmen dieser Optionen empfangen, damit der King Store-Kontext weiß, wie er mit Ihrer Datenbank spricht. Wir sehen später, wie man eine Verbindungszeichenfolge in die App einführt. Doch so deklarieren Sie Ihren Kontext. Und als Nächstes muss man Merkmale festlegen, die die Zuordnung zwischen deinen Objekten und Tabellen der Datenbank darstellen. Also, dafür führst du Folgendes aus: Wir definieren die folgenden Eigenschaften, die wir festlegen werden, damit der Code die vorgesehenen Parameter besitzt. Öffentliche DB: Spielesammlung. Dafür nutzen wir control.here, Cantor, diese API und Modelle, und nennen wir dieses Objekt hier 'games', damit der Zweck klar ist. Jetzt hat das weder Gather noch Set, sondern ist einfach eine Eigenschaft, die direkt auf ein Spiel-Set verweist. Also handelt es sich wirklich um ein Objekt, das sowohl zum Abfragen als auch zum Speichern von Spielinstanzen in diesem Fall verwendet werden kann, und alle Linkabfragen, die Sie an dieses Spieleobjekt senden, werden in Abfragen gegen die Datenbank übersetzt. Und genauso wie wir die Menge der Spiele definieren, möchten wir auch eine Menge für unsere Gens definieren. Also definieren wir unsere öffentliche Gen-Menge. Bezugnehmend auf Re, wird es künftig auf eine Menge von Genen wohl aufzeigen. Dann ist das alles, was wir tun müssen, um DB-Kontext zu definieren. Aber noch eine weitere Sache: Wir müssen uns tatsächlich registrieren. Dieser Datenbankkontext, damit er in unserer gesamten Anwendung verwendet werden kann. Und dazu gehen wir in unseren Datei-Explorer. Lass uns in unsere C#-Datei gehen. Und wie wir Validierungsdienste hinzugefügt haben, können wir auch unseren DB-Kontext nutzen, indem wir ihn einsetzen. Muster heißt Abhängigkeitsinjektion. Später lernen wir in diesem Kurs mehr über DI; aber ich zeige dir heute nur etwas. Wie man die Verbindungszeichenfolge definiert, um sich mit der Esq Lite-Datenbank zu verbinden, und wie man den DB-Kontext mit dieser Zeichenfolge registriert. Zunächst wird diese Verbindungszeichenfolge definiert. Hier definieren wir einfach eine Variable und stellen sicher, dass dies vor der Erstellung Ihres App-Objekts geschieht. Es muss vorher erfolgen, damit es ordnungsgemäß registriert wird. Bar-Beschränkung Und hier verwenden Sie die korrekte Syntax für eine Verbindungszeichenfolge. Das zielt auf eine SQI-Datenbank ab. Daher soll hier die Datenquelle dem Gleichheitszeichen zugeordnet werden, und auf der rechten Seite dieses Gleichheitszeichens geben wir den Namen der physischen Datei an, die die Datenbank repräsentiert. In diesem Fall nennen wir sie einfach game store dot db. Es muss nicht dieser Name sein; wirklich jeder Name wäre möglich. Es sollte etwas sein, das den Zweck der Datenbank wiedergibt, und da wir nun die Verbindung festgelegt haben, können wir fortfahren und unseren neuen DB-Kontext mit dieser Verbindung registrieren. Dafür verwenden wir Builder, der auch Dienste anbietet, die hinzufügen und eskalieren. Und hier als Typparameter möchten wir ausdrücklich unseren Game-Store-Kontext festlegen, der übrigens durch ctrl.here verwendet wird, um den Game-Store, diese API sowie diese Daten ganz gezielt zu nutzen. Und dann geben wir hier den eigentlichen Verbindungsstring an. C#-String. Damit ist unsere Anwendung bereit, mit der SQL-Datenbank zu sprechen. Wir haben doch noch nicht die Datenbankdatei erstellt, damit die Anwendung mit ihr sprechen kann. Und dazu können wir auch die Migrationsfunktion des Entity Framework Core verwenden. Eine Datenbankmigration ist der Prozess, bei dem schrittweise das Schema der Datenbank aktualisiert wird, um es mit dem Datenmodell der Anwendung in Einklang zu bringen und dabei vorhandene Daten in der Datenbank zu erhalten. In diesem Fall haben wir keine Datenbank, daher müssen wir eine Migration durchführen, um das anfängliche Schema der Datenbank zu erstellen. Dazu brauchen wir zwei Dinge. Zuerst benötigen wir das .NET EF-Werkzeug, das die Befehle bereitstellt, die erforderlich sind, damit die Migration eingeleitet und gestartet werden kann. Dafür gehen wir hier zu unserer NuGet.org-Seite, und im Suchfeld können wir ganz einfach nach .NET suchen. EF, dann klicken wir bitte auf Suchen. Das sollte zweifellos das allererste Ergebnis darstellen. Hier drüben sehen Sie den NET EF. Und hier möchten wir die neueste stabile Version des Pakets auswählen, die hier als Version 10.0 0.1 angegeben ist. Zum Zeitpunkt meiner Aufnahme kopieren wir diese Befehlszeile oben. Also kopieren wir sie zurück in VS Code. Öffnen wir nun unser Terminal Contra J. Lasst uns das Kopierte mit Leerzeichen versehen. Beachtet, dass dies ein globales Werkzeug sein wird. Also ist dies ein globales Werkzeug. Es hat nichts mit dem aktuellen Standort Ihres Projekts zu tun. Sobald Sie es installieren, wird es für jedes Projekt auf Ihrem Computer verfügbar sein. Und drücken Sie Enter. und Tool installiert. Als Nächstes benötigen wir bitte ein neues NuGet-Paket. Also schließen wir das hier jetzt. Gehen wir jetzt zurück in unseren Lösungs-Explorer. In diesem Fall klicken wir bitte mit der rechten Maustaste auf das NuGet-Paket 'Game Store API'. Und das Paket, nach dem wir suchen, ist genau dieses hier, genannt Microsoft dot Antide Framework, Core.Design. Drücken wir Enter. Es wird das Erste in der Liste sein. Geben wir den Framework-Code ein, das Design. Wählen wir die neueste stabile Version aus, 10.0 0.1, und das Paket ist installiert; wir können bestätigen, dass das Paket vorhanden ist, indem wir zu den Abhängigkeiten der Pakete gehen. Unser Paket befindet sich hier, und wir könnten es auch bestätigen, indem wir in die Projektdatei gehen. Wir sollten hier das installierte Paket sehen können. Nun, der Grund, warum wir dieses No-Package brauchen, ist, dass es im Wesentlichen das Gehirn der EF Core-Tools ist. Es liefert das .NET-EF-Tool. Die zusätzlichen Dienste, um Kontext zu entdecken und Modell zu erstellen. Dadurch erzeugt Migrationen, Scaffold und Code. und paar Dinge. Also, da wir jetzt das .NET Entity Framework installiert haben und das NuGet-Paket vorhanden ist, können wir sofort fortfahren und unsere erste Migration erstellen. Dafür öffnen wir unser Terminal. Dann bereinigen wir hier alles und wechseln in unser Game Store API-Verzeichnis. Also: Game Store API. Um das Tool auszuführen, fügen wir hier mit .NET EF-Migrationen eine neue Migration hinzu. Dafür müssen wir einen Namen für diese Migration angeben, der in diesem Fall die anfängliche Erstellung sein wird. Also nennen wir sie einfach Anfangserstellung. Und außerdem finde ich es praktisch, eine Zuordnung der erzeugten Dateien bereitzustellen. Das klappt damit, Dash-Ausgabe, mein Lieber. Dann wollen wir Zuordnung auswählen. Lassen Sie uns kurz unseren Datei-Explorer Contra E ansehen, um zu verstehen, wo wir diese Migration erzeugen sollten. Lassen wir das kurz zuklappen. Wir möchten unter unserem Datenverzeichnis gehen, direkt darin. Dort befinden sich unsere EF-verknüpften Dateien. Also, was Apple Deer betrifft, lassen wir hier jetzt Daten eingeben, und danach legen wir ebenfalls ein Migrationsverzeichnis an. Okay, also, das ist unser wirklich vollständiger Befehl. Drücken wir Enter. Und jetzt wird das Tool unsere Anwendung vollständig erstellen und anschließend alle Datenbank-Migrationsdateien vollständig erzeugen, eben. Nun, gehen wir wieder in den Datei-Explorer; dort sollte stehen, dass ein neuer Migrationsordner erstellt wurde. Öffnen wir ihn, finden wir einige Dateien. Die soeben erzeugte Migration repräsentiert. Nun, unter diesen Dateien schauen wir uns tatsächlich die allererste Datei an. Diese hier endet mit "initial create". Übrigens wird hier eine Nummer stehen, die dem Datum und der Uhrzeit entspricht, zu der du diese Migration erzeugt hast. Aber jetzt, wenn wir "initial" öffnen, diese Cs hier erzeugen, lass uns das hier und jenes zusammenklappen. Wir sehen, dass es so wird. Nur eine weitere Klasse, die in diesem Fall aus Migrationen stammt, von EF Core kommt und einige Methoden hat. Die erste Methode hier ist die Op-Methode. Es gibt jene, die die Logik enthält, Ihre Datenbank vom aktuellen Zustand in den neuen Zustand zu überführen. Und hier sehen Sie, wie die Create-Table-Methode aufgerufen wird, um die Erstellung dieser neuen Tabelle in der Datenbank zu definieren. Diese Tabelle wird unsere großzügige Tabelle sein. Wir legen Spalten fest, die in die Tabelle aufgenommen werden müssen, und legen fest, dass der Primärschlüssel der großzügigen Tabelle sein soll. Nachdem diese Tabelle festgelegt ist, erstellen wir die zweite und wichtigste Tabelle: unsere Spiele-Tabelle. Hier sehen wir die Spieltabelle; hier sind alle Spalten, die zu dieser Tabelle gehören und sich heute ganz eindeutig zuordnen lassen. Das Spielmodell in unserem C#-Code. Mir fällt auf, dass dieses hier tatsächlich alle richtigen Datentypen für die Datenbank definiert. Datenbank deeskalieren. Wenn wir weiter nach unten gehen, finden wir auch die Einschränkungen dieser Tabelle, nämlich den Primärschlüssel der Games-Tabelle und außerdem den Fremdschlüssel, der unsere erzeugte ID in der Games-Tabelle mit der ID der Genre-Tabelle verbindet. Wenn wir weiter nach unten gehen, finden wir außerdem den normalen Index, der auf dieser Tabelle definiert ist. Die Spalte, die als Fremdschlüssel ausgewählt wurde — in diesem Fall die generierte ID. Wie bei der Op-Methode haben wir auch die Down-Methode, die dazu dient, das Schema wieder in den vorherigen Zustand zu versetzen. Falls du jemals mal einen Migrationsschritt entfernen musst, Dies ist die Logik, die zuerst die Games-Tabelle löscht und danach die großzügige Tabelle löscht. Sie folgt der richtigen Reihenfolge, damit die Schritte gelingen. Nun, da wir unsere Migrationsdateien erzeugt haben, ist es an der Zeit, die Action-Migration auszuführen, und das können wir erneut über das .NET EF-Tool tun. Also schließe ich einfach alle diese Dateien. Lass uns zurück in unser Terminal gehen. Ich werde das hier tun und den folgenden Befehl ausführen: net EF database update. Drücke Enter, und das ist der Befehl, der all den Migrationscode nimmt und ihn auf unserem Rechner ausführt, um eine erste Version unserer Datenbank zu erstellen. Lass mich Terminalausgabe erweitern. Wir sehen hier viele Zeilen. Wie Sie sehen, besteht hier eine Menge SQL-Befehle, die ausgeführt wurden, um unsere SQL-Datenbank zu erstellen. Und dazu gehe ich nicht weiter ins Detail. Jeder Befehl im Detail, aber hier sind folgende Punkte zu beachten. Zum Beispiel haben wir hier unsere EF-Migrations-Historietabelle direkt hier, die dazu dient, die zuletzt auf Ihre Datenbank angewendete Migration genau zu verfolgen, damit bei der nächsten Migration bekannt ist, von welcher Migration aus gestartet werden muss. Wir gehen weiter runter und sehen, dass die Migration hier angewendet wird. So wird genau die Migration verwendet, die wir eben erstellt haben, und das bedeutet, dass sie ein paar Dinge tun muss, oder? So muss sie unsere Migrations-Tabelle erstellen. Hier ist die Migrations-Tabelle. Dann muss sie die Games-Tabelle hier erstellen, und danach führt sie weitere Befehle aus. Außerdem wende den Index an, richtig? Der Index für den Fremdschlüssel fügt unsere neue Migration in die EF-Migrationsverlaufstabelle ein, und danach wird die Migration abgeschlossen. Und weil all das jetzt erledigt ist, sollten wir sehen können, ob wir im Datei-Explorer zurückgehen können. Vielleicht klappen wir das Terminal zusammen. Zunächst sollten wir erkennen, dass hier unsere brandneue DV-Datei vom Spiele-Shop generiert wurde. Also ist unsere Datenbank jetzt aktiv. Und an diesem Punkt ist es nicht verkehrt, diese Datenbank zu durchsuchen, um zu prüfen, ob das richtige Schema erzeugt wurde. Und der Weg dazu besteht darin, eine neue VS Code-Erweiterung zu installieren. Dann lasse ich für einen Moment meine Aktivleiste öffnen. Fokusleiste. Lass uns hier in den Erweiterungsbereich gehen, und diesmal suchen wir nach der SQ light-Erweiterung. Es wird diese hier sein, SQ light. Hier ist dieses Auto. Wie dort zu sehen ist, ist Alex C# v C# C#, eine sehr beliebte Erweiterung. Es ist sehr einfach, aber sehr praktisch, um Ihr S-Schema zu erkunden. Klicken wir also auf Installieren. Okay, installiert. Also schließen wir das. Gehen wir in unseren Datei-Explorer zurück. Jetzt haben wir die Erweiterung; was tun wir? Führe einen Rechtsklick auf die Game Store DB aus, und dort werden wir einen brandneuen Befehl finden, der 'Open database' heißt und oben angezeigt wird. Wenn wir darauf klicken, öffnet sich auf der linken Seite ein völlig neuer Bereich, der den Namen 'SQ Light Explorer' trägt. Okay, jetzt, bevor wir dahin gehen, lasse ich kurz meine Aktivleiste aus, damit wir besser sehen können – und vielleicht auch meine Menüleiste. Danach öffnen wir den Explorer. Was wir sehen werden, ist, dass unsere Datenbank hier liegt, und wir können beginnen, Dinge zu erweitern, um das Schema der Datenbank zu erkunden. Also wie gesagt: Hier ist unsere EF-Migrationsverlaufstabelle, genau, richtig? Sie enthält wirklich die Migration, die wir gerade ausgeführt haben. Um zu sehen, was drin steht, klicken wir hier auf den Play-Button, bitte. Und ja, der Inhalt ist so beschrieben. Hier ist die Idee unserer Migration, und wir haben die EF Core-Version, die diese Migration erzeugt. Wie gesagt, so verfolgt EF Core die zuletzt verwendete Migration, damit die nächste Migration weiß, wie sie auszuführen ist, sobald sie kommt. Hier haben wir unsere Tabelle. Wir sehen Spalten, ID und Name, Datentypen. Und klar haben wir unsere Spieltabelle mit allen entsprechenden Spalten, wie üblich. Nun, eine Sache, die ich für die lokale Entwicklung wirklich nützlich finde, ist, beim Start der App etwas Code hinzuzufügen, damit die neuesten Migrationen immer beim Start angewendet werden. So müssen wir das .NET nicht ständig laufen lassen. EF-Datenbank-Update-Befehl jedes Mal, wenn wir eine Migration vornehmen. Dann zeige ich dir jetzt, wie das geht. Gehen wir doch wieder in unseren Explorer. Oder eigentlich ist es unser Solution Explorer, weil wir eine ganz neue Klasse erstellen müssen, die wir hier in unser Datenverzeichnis einfügen werden. Machen wir Rechtsklick auf Neue Datei. Es wird eine Klasse sein. Benennen wir sie hier: Data Extensions. Öffnen wir Extensions.cs. Bereinigen wir die Using-Anweisungen, und dies wird eine statische Klasse sein, weil sie eine Erweiterungsmethode haben wird, die wir aufrufen werden – public void oder public static void migrate. Diese Vorgehensweise wird unsere Webanwendungsklasse App umfassend erweitern. und der Code, den wir hier haben, wird recht einfach sein Zuerst. Wir erstellen etwas, das man Umfang bezeichnet. Was nötig ist, damit wir Zugriff auf eine Instanz unseres GameStore-Kontexts erhalten. Das hängt mit der Dependency-Injection von ASP.NET Core zusammen, das wir im Kurs später behandeln werden. Also, mach dir bitte keine Sorgen. Ich werde das später noch detaillierter erläutern. Allerdings beginnen wir vorläufig damit, die folgenden Zeilen jetzt einzugeben. Wir verwenden daher VAR-Scope gleich App, das Dienste bietet, die erzeugen. Der Umfang. Und danach besteht die Möglichkeit, eine vollständige Instanz des DbContext abzurufen, indem wir den folgenden Ausdruck verwenden: var dbContext = scope.ServiceProvider.GetRequiredService<GameStoreContext>(); Vielleicht schick ich's zur nächsten Folie, damit wir's besser sehen. Und jetzt, da wir Zugriff auf eine Instanz des DV-Kontexts haben, können wir jene Datenbank migrieren, ohne weitere Verzögerung. Noch einmal: Wir bekommen es. Zuerst im Service-Scope gibt es Zugriff, in dieser Migrate-DB-Methode eine Instanz des Game Store-Kontexts abzurufen oder zu erstellen. Dann nutzen wir den DB-Kontext, um DB zuzugreifen und alle Migrationen durchzuführen. Nun, um das hier zu verwenden, gehen wir zurück zu unserem Programm, das die C#-Datei ist. Also gehen wir erneut zum Datei-Explorer. Und diese Methode müssen wir nach der Erstellung unseres Webanwendungsobjekts dort aufrufen. Also machen wir das vielleicht hier in Zeile 15, bevor die Anwendung gestartet wird. Rufen wir einfach den Befehl 'app migrate db' auf. Jetzt testen wir endlich unsere neue Logik im Praxistest. Und dazu gehen wir jetzt wieder in den Dateiexplorer. Und was ich jetzt tun werde: Meine Game-Store-DB-Datei zu löschen, damit sie beim Start der Anwendung automatisch neu erstellt wird – so wie unser Code es tun sollte. Also klicken wir hier mit der rechten Maustaste darauf. Lass uns jetzt bitte die Datei löschen; sie ist gelöscht. Jetzt öffnen wir unsere Kommandozeile auf J. Ich werde das hier bereinigen, und wir starten einfach die Anwendung. Dann tippe ich dotnet, run, Enter und bestätige es. Und wir können klar sehen, dass die Datenbankdatei automatisch erzeugt wurde. Also ab jetzt müssen wir nun nur noch die neue Migration in unseren Code einfügen, und beim Start der App wird sie automatisch auf unsere Datenbank angewendet. Eine weitere Sache, die ich an dieser Stelle gerne tun möchte, ist die Menge des Loggings von EF Core zu reduzieren, das jedes Mal entsteht, wenn dieser Migrationscode ausgeführt wird. Wie man sieht, wird hier viel geloggt – hilfreich, um zu verstehen, was hinter den Kulissen passiert –, doch wenn wir all dies ansehen, wird es einfach doppelt so viel sein. Jedes Mal, wenn wir die Anwendung starten. Um die Protokollausgaben zu reduzieren, folgt Folgendes. Wir stoppen die Anwendung einfach. Strg+C wird mein Terminal schließen, und wir gehen zur JSON-Datei. In diesem Kurs befasse ich mich nicht mit dem ASP.NET Core-Login. Aber Sie sollten wissen: Sie können das Logging der verschiedenen Teile der .NET- und ASP.NET Core-Bibliotheken durch Änderung des Log-Levels steuern. Hier in der Website-JSON-Datei, Hier sehen Sie eben, dass das standardmäßige Protokollierungsniveau dem Informationsniveau entspricht. Auch das Protokollierungsniveau der Bibliotheken, die zum Microsoft .NET-Koordinatenraum gehören. Wir können hier auch unsere eigene Einstellung für das Protokollierungsniveau von Entity Framework und Core-Datenbankbefehl festlegen. Also hier können wir Microsoft, dieses Entity Framework oder diese Datenbank auswählen, diesen Befehl. Und in diesem Fall wird Folgendes wirklich umgesetzt. Wir reduzieren das Protokollierungs-Level so, dass wir ausschließlich Meldungen im Protokoll sehen, die mindestens dem Warnlevel entsprechen. Das bedeutet, Warnungen, Fehler und kritische Meldungen werden angezeigt, während Informationsprotokollierung, Nachverfolgung oder Entwicklungsnachrichten nicht angezeigt werden. Ich gebe hier eine Warnung aus. Das sollte die Logs in der Konsole senken. Probieren wir es aus. Gehen wir zurück in den Datei-Explorer. Löschen wir Game-Store-TV. Deshalb mag ich Esq Light, um das zu lernen, denn die Datenbank lässt sich leicht löschen. Also ist es weg. Und jetzt kehren wir nun zum Terminal zurück. Starten wir die App. Wie man sieht, sind SQL-Anweisungen verschwunden. Sie werden zwar ausgeführt, erscheinen aber nicht in den Logs, weil wir die Protokollierung reduzieren. Sie können das später ändern, falls nötig; aber im Rest des Kurses sollte es funktionieren. Jetzt ist es an der Zeit, unsere neue Datenbank an unseren Endpunkten zu nutzen, damit alle Endpunkte stabil arbeiten. Bevor wir das tun, brauchen wir vermutlich erst Daten in der neuen, großzügigen Tabelle. Wenn wir jetzt die Tabelle kurz prüfen, gehen wir zum SQL-Light-Explorer, klappen ihn zu, und schauen dann in die großzügige Tabelle; vielleicht nehmen wir sie hierher mit und testen später erneut, und alles funktioniert gut. Wir werden schon sehen, dass der Tisch völlig leer ist. Deshalb können wir über unsere Spiele-Endpunkte jetzt keine Spiele erstellen. Da der Fremdschlüssel bald verlangt, dass wir zuerst etwas in der zugehörigen Tabelle haben. Also, wir bauen keine Endpunkte, um unsere großzügige Tabelle zu füllen; was wir tun können. Fülle unsere Datenbank mit Beispieldaten. Wenn die Anwendung läuft, befüllen wir sie mit Beispieldaten, die wir später für Spiel-Endpunkte benötigen. Also zeige ich dir, wie's geht. Schließen wir das hier. Lassen wir auch unseren Server jetzt stoppen. Und gleich zurück zu unserer C#-Datei. Lass mich schließen. Andere Tabs gehen hierher zurück. Lass uns den Teil finden, indem wir unser ES-Licht hinzufügen. Hier. Wir können außerdem Optionen der Add-ESCAL-Lichtmethode verwenden, um auch die Datenbank zu sehen. Sobald es sogleich erstellt wird. Also, lass uns das machen. Lass uns das wirklich in die nächste Zeile senden. Lasst uns bitte das jetzt tun und einen weiteren Parameter hinzufügen. Das wird unsere Optionenaktion sein. Das ist also ein Delegat, der die Funktion bereitstellt, die nach der Erstellung der Datenbank ausgeführt wird, damit wir die Datenbank ordnungsgemäß befüllen können. Also lasst uns Optionen wirklich verwenden. Und hier rufen wir die Optionen auf, die Seed-Verfahren verwenden. Klammern, dies empfängt einen Parameter, der unser DV-Kontext sein wird. Also Kontext, hier wird es einen weiteren Parameter geben, den wir nicht verwenden werden, also lass ihn dort einfach mit einem Unterstrich verwerfen, und dann liefern wir hier die eigentliche Logik, indem wir unsere Abfrageklammern öffnen und schließen. Und die Logik hier wird so aussehen: Falls kein Kontext vorhanden ist, dieses konkrete Set. Dies wird uns eines der DV-Sets im Datenbankkontext liefern, und dieses konkrete Set wird das großzügige Set sein, das wir im weiteren Verlauf betrachten. Okay. Irgendwas, und bevor wir fortfahren, drücken wir bitte Strg. Punkt bei Erzeugen, damit wir unsere Game-Store-API verwenden können, die den Namensraum wirklich abbildet. Okay. Also falls wir nichts finden sollten. In der großen Tabelle sollte dies der Fall sein. Wenn die Datenbank gerade erstellt wird, führen wir die folgende Logik aus. Wir werden den Kontext klar, ausführlich und eindeutig angeben, der Gen festlegt, der Reichweite erweitert, und hier werden wir es schrittweise einführen, zur besseren Nachvollziehbarkeit. Unser erstes Spiel ist großzügig. Dafür können wir das so machen. Wir können doch eine neue Gen. Legen wir zum Beispiel, ganz einfach, einen Namen fest. Unser erster wird auf lange Sicht kämpfen und. Und auf dieselbe Weise können wir auch einige weitere Genres einführen, die unser Portfolio sinnvoll ergänzen und unseren Nutzern mehr Auswahl bieten. Also werde ich sie hier zunächst nicht manuell eintippen, sondern vorerst so belassen, dass sie hier vor Ort sichtbar bleiben. Ich füge sie hier tatsächlich ganz einfach aus meinem Spickzettel ein. Dort. Also haben wir jetzt fünf Spiele, die bereit sind, mit einem unserer kommenden Spiele in der Datenbank verknüpft zu werden. Natürlich müssen wir uns auch daran erinnern, diese Informationen in der Datenbank zu speichern, und wir können das tun, indem wir den DV-Kontext bzw. Kontext aufrufen, der die SaveChanges-Methode ausführt, wie hier gezeigt wird. Super. So mit diesem sollten wir nun bereit sein, die Datenbank zu sehen. Wenn die App startet. Lass uns das Terminal noch einmal öffnen. Öffne Terminal und räume auf. Lass uns mal net run starten. Okay, und jetzt werfen wir schnell einen Blick in unsere Datenbank, Contra Shift E. Werfen wir erneut hier einen Blick hinein, um den Inhalt der großzügigen Tabelle zu sehen. Klick dort hin, und tatsächlich übernehmen wir das hierher. Jetzt sehen wir, dass unsere anfänglichen großzügigen Einträge vollständig in die Datenbank übernommen wurden. Datenbank läuft wie erwartet. Nun, wie bei allem Übrigen auch, lasse ich diese Logik nicht direkt auf dem gleichen Niveau wie C#, denn wieder einmal wird sie von zu viel Logik aufgebläht, die die Datei größer macht und schwer zu verstehen ist. Also tun wir Folgendes: Wir stoppen hier meinen Server und verschieben all die Datenbanklogik in eine neue Erweiterungsmethode, damit wir hier nur eine Zeile aufrufen müssen, um all diese Logik zu starten. Also, dafür gehen wir zurück zu contrive E. Öffnen wir den Explorer, gehen in die Daten und in unsere Daten-Erweiterungen, zur CS-Datei. Denk daran, dass hier unsere DB-Migrations-Erweiterungsmethode liegt; daher ist sie gut geeignet, eine Methode einzuführen. Um sehr umfassend und ordnungsgemäß unsere Datenbankdienste und auch unsere anfängliche Datenbefüllung zu registrieren. Unter dieser Methode fassen wir daher eine neue hinzu, die wir Public Static Void bei GameStoreDb nennen werden. Diese wird unseren WebApplicationBuilder schrittweise und umfassend erweitern. Und hier übernehmen wir einfach die gesamte Logik, einschließlich unserer Verbindungszeichenfolge, und zwar bis hierher. Lass uns doch einfach alles hier entfernen und es hierher rüberbringen, bitte. Okay, lass uns unter Generate hier das C#-Steuerelement auswählen, damit wir unsere Game Store API einführen. Dieses Modell liegt im Geltungsbereich, und die Logik wurde nun vollständig außerhalb von Program.cs verschoben. Jetzt können wir wieder in das C#-Programm gehen und direkt danach. Unser Ad-Validierungsaufruf; wir können jetzt builder.at GameStoreDB aufrufen, was eine saubere Datei ergibt. Nochmals können wir unnötige Using-Anweisungen entfernen, um den Code sauberer zu halten. Also läuft bisher alles gut. Aber eine Sache ist zu beachten: Wenn Sie in die Daten-Erweiterungen zurückgehen, die Cs betreffen, ist es so, dass wir diese hartkodierte Verbindungszeichenfolge direkt in unserem C#-Code belassen. Das ist wirklich nicht ideal, denn sobald wir versuchen, die Anwendung in eine andere Umgebung zu verschieben, zum Beispiel in die Produktion, müssen wir die Verbindungszeichenfolge direkt im Code vollständig ändern, damit sie in die Produktion bereitgestellt werden kann. Und falls wir wieder zur Entwicklung wechseln müssen, ändern wir es zurück auf diesen lokalen String. Das wird sicher fehlerhaft und problematisch. Lass uns Pause machen, um mehr über das SVnet-Konfigurationssystem zu erfahren. und wie es uns bei diesem hartkodierten String hilft Zu diesem Zeitpunkt haben wir die Verbindungszeichenfolge fest in unseren Anwendungscode eingebaut, um direkt mit unserer Datenbank zu kommunizieren. Allerdings ist das nicht ideal, denn wenn wir die API später in eine andere Umgebung verschieben, zum Beispiel in eine Cloud-Bereitstellung, wird die Verbindungszeichenfolge anders sein und wir müssten zusätzlichen Code ändern. Glücklicherweise gibt es wirklich bessere Orte, um die Anwendungskonfiguration zu speichern. Eine der beliebtesten Optionen in .NET Core, insbesondere für die lokale Entwicklung. Die appsettings.json-Datei, die alle Arten von Konfigurationsinformationen im JSON-Format speichern kann. Nun ist die appsettings.json-Datei eine Konfigurationsquelle; wie diese gibt es weitere Konfigurationsquellen, die in .NET-Anwendungen unterstützt werden, etwa Befehlszeilenargumente, Umgebungsvariablen, Benutzergeheimnisse und sogar cloudbasierte Quellen wie Azure Key Vault. Und das Tolle daran ist, dass SG-Net-Core seine Infos aus allen verfügbaren Konfigurationsquellen in ein einziges Konfigurationsobjekt bündelt, das die I-Schnittstelle implementiert. Dieses Konfigurationsobjekt ist für Ihre beste API eben so leicht zugänglich, dass es im Grunde nicht wissen muss, woher die Daten tatsächlich stammen. In diesem Tutorial speicherst du deinen Verbindungsstring in der Datei neben der Website. Beachte, dass dies nur eine zulässige Option ist, da du keine Zugangsdaten brauchst, um dich mit deiner SQLite-Instanz zu verbinden. Für lokale Entwicklung: Falls Sie eine Datenbank-Instanz mit Zugangsdaten verwenden, verwenden Sie bitte die User-Secrets-Konfigurationsquelle, die durch den NET Core Secret Manager aktiviert ist. Speichern Sie niemals Zugangsdaten in Ihrer Website, insbesondere in dieser JSON-Datei. Lass uns jetzt SAPI updaten, damit sie den Verbindungsstring aus JSON lesen kann. Schauen wir uns an, wie man das ASP.NET Core-Konfigurationssystem verwendet, damit die Verbindungszeichenfolge nicht mehr hart in unseren C#-Dateien codiert wird. Fangen wir hier in appsettings.json an und klappen das zusammen. Also führen wir hier unseren Verbindungsstring ein, indem wir in dieser Datei einen gut bekannten Schlüssel verwenden. Also öffnen wir hier nun einen weiteren Abschnitt und nennen ihn Verbindungsstring. Lass uns diesen Abschnitt öffnen und unsere Verbindungszeichenfolge als Schlüssel-Wert-Paar verwenden. Da dies die Verbindungszeichenfolge der Game Store-Datenbank ist, können wir etwas Einfaches wie Game Store als Schlüssel verwenden. Und dann für den Wert: Wir wollen dieselbe Verbindungszeichenfolge verwenden, die wir bisher im Code nutzen. Also führe ich Kontrastverschiebung E aus. Um wieder in unsere Daten und Erweiterungen zu gelangen, diese CS-Datei; Denk daran, unsere Verbindungszeichenfolge liegt hier in der GameStore-DV-Methode. Es ist hier; kopiere es. Und ich füge es hier ein. So speicherst du deine Verbindungszeichenfolge in der Config, damit das .NET Core-Konfigurationssystem sie einfach lesen kann. Aber klar, wir müssen jetzt wirklich Data Extensions ändern, damit wir das System nutzen können. Dafür müssen wir Folgendes tun. Also hier ersetzen wir dies durch einen Aufruf an den Builder, jene Konfiguration, die die Verbindungszeichenfolge erhält, und der Parameter zu dieser Methode wird der Schlüssel der Verbindungszeichenfolge sein, den du gerade definiert hast. Also kehren wir nun zum JSON zurück; dieser Schlüssel wird 'game store' sein. Also kopieren wir das mal. Hierher zurück. Wir fügen es dort ein. Und die Zeile beenden. Das ist, was Sie tun müssen, um Ihre Konfiguration aus Apps-Datei zu lesen und zu beweisen, dass es funktioniert. Setzen Sie hier mal einen Haltepunkt in meiner Zeile. Starten wir die App und prüfen, ob wir den Verbindungsstream lesen können. Drücke F5. Hier sind wir. Lass uns das hier zusammenfassen, vielleicht auch dieses hier. Und wenn wir mit der Maus über die Verbindungszeichenfolge fahren, sehen wir, dass die Verbindungszeichenfolge tatsächlich von Abta Jason gelesen wurde. Hier braucht man Verbindungsstring nicht mehr hart zu kodieren. Ich klicke auf Play, und die App startet normal. Allerdings ist die Stärke des Konfigurationssystems, dass du die Verbindungszeichenfolge nun in jeder Umgebung nach Bedarf überschreiben kannst, etwa in einer Produktionsumgebung, und dir zeigen kannst, wie das funktionieren könnte. Lass uns Folgendes tun. Lass uns einfach diese Detox-Sitzung beenden. Lass uns Terminal öffnen. Ich wechsle hier zu einem echten Terminal. Öffne ein Terminal neu. Vielleicht schließen wir es mal. Und machen wir Folgendes. Lass mich maximieren. Wir legen jetzt den Verbindungsstring als Umgebungsvariable fest. Da ich hier PowerShell verwende, besteht der Weg darin, hier einen M-Aufruf mit dem Namen der Umgebungsvariable anzugeben. Jetzt soll hier ein Name verwendet werden, bitte; lass es kurz zusammenfassen, denn der Name wird Jason sein. ist dazu fähig Folge einer gut bekannten Hierarchie von Namen, um Dinge in die Konfiguration abzubilden. In diesem Fall kann ich daher den Namen meiner Umgebungsvariablen mit dem Wort Verbindungszeichenfolge so beginnen. Danach trenne ich diesen Schlüssel vom Unter-Schlüssel, indem ich zwei Doppelpunkte verwende, und dann können wir den nächsten Namen platzieren. Im Konfigurationsschlüssel wie hier setze ich dann ein Gleichheitszeichen und anschließend den eigentlichen Wert ein, richtig? Ich kopiere den Wert. Hier, aber diesmal, um zu beweisen, dass das tatsächlich funktionieren wird, werde ich den Namen der Datenbank ändern. Also stellen wir uns vor, dass wir uns jetzt in der Produktion befinden. Wir legen eine Umgebungsvariable für eine andere Datenbank fest. Nennen wir sie production db, und drücke Enter. Wenn das funktioniert, sollten wir am Ende diese neue Datenbank erhalten, wenn wir die Anwendung diesmal mit einem einfachen Aufruf von dotnet run ausführen. Also wechseln wir in unser Game Store API-Verzeichnis hinein, und bevor wir dot und Run ausführen, öffnen wir vielleicht unseren Datei-Explorer-Fenster, um zu prüfen, dass unsere Datenbank bisher noch Game Store db heißt. Aber jetzt, wenn wir .NET Run ausführen, während hier diese neuen Umgebungsvariablen für eine passende Konfiguration gesetzt sind, drücken wir Enter. Und was wir sehen, ist, dass eine brandneue Datenbank – unsere Produktionsdatenbank – jetzt erstellt wird, weil die Anwendung nun glaubt, dass dies der neue Wert für unsere Konfiguration ist. Beachten Sie, dass sie die Migration sogar noch einmal angewendet hat. Es ist eine neue Datenbank. Also nur dadurch, dass man diesen brandneuen Wert im Terminal als Umgebungsvariable setzt, konnten wir die Konfiguration vollständig ändern, ohne jemals unseren C#-Code anfassen zu müssen. Der C#-Code ist derselbe, den Sie gesehen haben, der die Konfiguration liest. Er weiß wirklich nicht, woher die Konfiguration kommt. Und genau das macht das ASP.NET Core-Konfigurationssystem sehr leistungsfähig und flexibel, sodass derselbe Code in vielen Umgebungen funktionieren kann. Nun, da ich diese Umgebungsvariable in meiner Terminal-Sitzung gesetzt habe, wird sie verschwinden, sobald ich das Terminal beende. Und zum Bestätigen gehen wir zurück und öffnen Terminal erneut. Lass uns Strg-C verwenden, um die Anwendung zu stoppen. Lass uns dieses Terminal einfach schließen. Gehen wir zurück in den Dateiexplorer und löschen diese neue Produktionsdatenbankdatei, die wir erstellt haben. Löschen. Es ist weg. Und jetzt, falls ich mein Terminal erneut öffne, gehen wir wieder hinein, API speichern und dann ausführen. Die App wird jetzt starten, aber sie wird wieder aus unserer JSON-Datei lesen, richtig? Sie wird hier lesen, denn es gibt keine Umgebungsvariable mehr. Und man sieht auf der linken Seite, dass wir wieder in der Instore-Datenbank sind. Es gibt keine Produktionsdatenbank mehr. Und damit sind wir mit dem Konfigurationsteil der Anwendung fertig, und es ist Zeit, die Vorteile aus unserer neuen Datenbank über unsere API-Endpunkte zu nutzen. Bevor wir das tun, müssen wir ein wirklich sehr wichtiges Konzept in ASP.NET Core lernen, Es ist als DI-System bekannt. Machen wir hier bitte eine kurze Pause, um mehr darüber zu erfahren. Um zu verstehen, was Abhängigkeitsinjektion ist, betrachten wir zwei Klassen: meinen Service und meinen Logger. Mein Service verwendet Logging, diese Methode meines Loggers, um Meldungen in eine Datei zu schreiben, wann immer mein Service eine Operation ausführt. Da mein Service einige Funktionen meines Loggers nutzt, wie das Logging, bleibt diese Methode bestehen, ja Wir sagen, dass mein Logger Abhängigkeit von meinem Dienst ist. Nun, damit mein Dienst in der Praxis meinen Logger verwenden kann, erstellt er im Konstruktor eine Instanz meines Loggers, und danach kann er beginnen, diese Methode aufzurufen. I. Auf den ersten Blick scheint dies hier kein Problem zu sein, aber bedenken Sie doch bitte, was geschieht, wenn die Autoren meines Loggers es leicht verändern, sodass ein neues Dateischreiber-Objekt im Konstruktor übergeben werden muss, weil dort jetzt die Ausgabedatei definiert ist. Die notwendigen Änderungen wirken einfach umzusetzen, zeigen aber einige wichtige Probleme. Mein Dienst ist äußerst eng an mein Logdatei-System gebunden, sodass sich jedes Mal, wenn sich mein Log ändert, auch mein Dienst angepasst werden muss – so wie hier, als der Konstruktor begann, eine Datei-Schreiber-Instanz zu verlangen. Mein Dienst muss wissen, wie man die My-Logger-Abhängigkeit aufbaut und konfiguriert, wie hier am Dateischreiber-Objekt, das auch mit einer passenden Datei eingerichtet werden muss, um die Ausgaben zu speichern. Das macht es schwer, meinen Dienst zu testen, da Unit-Tests meinen Logger nicht mocken oder seine Ausgabe stoppen können. Diese Log-Datei wird immer erzeugt, was die Tests verlangsamen würde. Falls die Tests Zugriff auf einen Ort zum Schreiben von Dateien haben, gibt es glücklicherweise eine bessere Lösung: Abhängigkeitsinjektion. Gehen wir zurück zu meinem Service, und es handelt sich um meine Logger-Abhängigkeit. Mein Service protokolliert diese Methode weiter; diesmal wird der Logger nicht explizit von meinem Service erzeugt. Stattdessen wird mein Logger als Konstruktorparameter übergeben. So muss mein Service nicht wissen, wie der Logger aufgebaut oder im Detail konfiguriert wird. Es nimmt es einfach entgegen und kann es sofort auch verwenden. Aber wenn mein Dienst den Logger nicht erzeugt, wer tut das denn dann? Nun, ASP.NET Core stellt den IServiceProvider bereit, der als Service-Container bezeichnet wird. Ihre Anwendung kann meinen Logger und alle anderen Abhängigkeiten während des Startvorgangs beim IServiceProvider registrieren, was typischerweise in Ihrem Programm, in dieser CS-Datei, geschieht. Dann später, wenn eine neue HTTP-Anfrage eingeht und Ihre Webanwendung eine Instanz meines Dienstes benötigt, erkennt der Service-Container diese Abhängigkeiten, löst sie auf, konstruiert sie und injiziert sie über den Konstruktor in eine neue Instanz meines Dienstes. Dies eröffnet Ihrer Anwendung eine Vielzahl praktischer, messbarer, sicherer und vielseitiger Vorteile. Zu Beginn bleibt mein Dienst von Änderungen an seinen Abhängigkeiten wirklich unberührt. Es ist egal, wie oft sich der Konstruktor meines Logs ändert; auch kein Grund, meinen Dienst zu ändern. Außerdem wird mein Dienst keine Instanzen meines Loggers erstellen, daher braucht er nicht zu wissen, wie man ihn baut oder einstellt. Und falls Ihre Anwendung Minimal-APIs nutzt, lassen sich Abhängigkeiten auch als Parameter an API-Endpunkte injizieren. Ich. Aber wann genau sollte ich als Dienstanbieter neue Instanzen erstellen? Wir wissen, dass beim Start Ihre App die Abhängigkeiten wie meinen Logger registrieren wird, und später, wenn eine HTTP-Anfrage eintrifft, wird der Serviceanbieter automatisch eine Instanz meines Loggers in eine neue Instanz Ihrer Klasse injizieren. Mein Dienst in diesem Beispiel; was nicht ganz klar ist, ist, was passiert, wenn nun eine neue Anfrage hier ankommt? Soll der Dienstanbieter für die neue Anfrage eine brandneue Logger-Instanz erstellen, oder soll er dieselbe Instanz wiederverwenden? Was passiert, wenn ein anderer Dienst, der ebenfalls von meinem Logger wirklich abhängig ist, im Zuge einer neuen Anfrage erstellt werden muss? Gib meine Logger-Instanz aus, oder eine neue. Die Antwort darauf liegt in der Lebensdauer des Dienstes. Anders gesagt: Wie lange jede Instanz auch leben soll. Es gibt drei Dienstlebensdauern: transient, scoped und singleton. Zurzeit richten wir unseren Fokus jedoch gezielt auf scoped, denn genau auf diese Weise registrieren Sie Ihren DbContext sicher und korrekt in Ihrer Anwendung. Angenommen, mein Logger ist eine Klasse, die einen Zustand verfolgt, der von mehreren Klassen, die an einer HTTP-Anfrage beteiligt sind, gemeinsam genutzt werden muss. In diesem Fall würden Sie meinen Logger hier mit der AddCode-Methode registrieren, sobald eine HTTP-Anfrage eintrifft. Der IServiceProvider wird auflösen, konstruieren und eine Instanz meines Loggers in meinen Dienst injizieren. Aber falls es einen weiteren Dienst gibt, der an derselben HTTP-Anfrage mitwirkt und ebenfalls von meinem Logger abhängt, erhält dieselbe Instanz dieser Abhängigkeit. Falls jedoch eine neue HTTP-Anfrage eingeht, erzeugt der Dienstcontainer eine, injiziert, eine völlig neue Instanz meines Loggers, die völlig unabhängig von der vorherigen Instanz ist. Daher werden Lebensdauer-Services pro HTTP-Anfrage einmal erzeugt und innerhalb dieser Anfrage wiederverwendet. Kehren wir nun zum Code zurück und betrachten das Lebenszyklus-Verhalten, indem wir den DB-Kontext in unsere API-Endpunkte injizieren. Lass uns sehen, wie man unseren DB-Kontext mit unseren API-Endpunkten nutzt, indem man DI-System effektiv verwendet. Also schauen wir uns unsere Endpunkte und die Spiele-Endpunkte an, nehmen wir uns das einen Moment lang vor, und beginnen wir einfach mit dem POST-Endpunkt, dem Endpunkt, der Spiele erstellt. Scrollen wir hier nach unten zu unserem Map-Aufruf. Um unseren DB-Kontext in diesen Endpunkt einzuführen, müssen wir ihn bitte lediglich als neuen Parameter in unserem Handler hinzufügen. Also nach unserem neuen DTO können wir dort ganz einfach den Game Store-Kontext und den DB-Kontext hinzufügen. Machen wir es hier, bitte, damit wir unseren Game Store verwenden können. Erzeuge bitte einen pi.data-Namensraum. das trägt dazu bei, dass der Service-Container läuft Löst Konstrukte auf und injiziert gleichzeitig eben eine neue Instanz des Game Store-Kontexts in den Endpunkt. Aber wo wurde der C#-Kontext eigentlich dafür registriert? Gehen wir schnell zurück in unser Programm, in diese CS-Datei. Und erinnern Sie sich daran, dass wir hier diesen Aufruf haben, der in der Game Store-Datenbank aufgerufen wird. Ich werde auf diesen hier klicken und F12 drücken, um zu sehen, was dort vor sich geht. Hier sollten wir uns daran erinnern, dass wir nach dem bloßen Abrufen der Verbindungszeichenfolge diesen Aufruf in SQLite des Typs Game Store Context ausführen. Dies ist der exakte Moment, in dem wir den R-Db-Kontext im Service-Container zur Vorbereitung auf die Abhängigkeitsinjektion registrieren. Und eines sollten Sie realisieren: Dieser Aufruf unterscheidet sich nicht allzu sehr davon, etwas Ähnliches wie builder.Services zu erstellen, das im Gültigkeitsbereich des GameStore-Kontexts liegt. Also registriert hier SQLite wirklich unseren Datenbank-Kontext mit einer Scoped-Service-Lebensdauer, ganz genauso, wie es Scope heute tun würde. Aber warum sollten wir den DB-Kontext als Scoped-Dienst registrieren, statt eines Singleton-Dienstes oder eines transienten Dienstes vielleicht. Es muss verstanden werden. Lass uns kurz reden. Ich entferne das hier und schreibe Kommentare, um es zu erklären. Der R‑DB-Kontext hat eine Scoped-Lebensdauer, denn diese Lebensdauer im Scope sorgt dafür, dass für jede einzelne Anfrage eine neue, frische Instanz des Kontexts erstellt und wieder verworfen wird. Wenn Sie kurz zu den Game-Endpunkten zurückgehen, müssen Sie verstehen, dass dies der Fall ist. Jedes Mal, wenn Ihr Map-Post-Endpunkt aufgerufen wird, wird eine brandneue Instanz von GameStoreContext erstellt, und sie besteht nur bis zum Ende der jeweiligen Methode. Sobald wir diesen Map-Endpunkt verlassen, wird der Kontext des Spielegeschäfts zerstört. Und wenn ein Aufruf an Map-Endpunkt oder an einen anderen Endpunkt eingeht, wird eine Instanz des Kontexts neu erstellt. Aber was ist das, was wir so wollten? Na ja, halt. Deswegen. Datenbankverbindungen sind eine begrenzte und relativ teure Ressource, daher wird der Umfang und die Lebensdauer des Kontextes dafür sorgen, dass die Verbindungen effizient geöffnet und geschlossen werden. Der Datenbankkontext Ist nicht thread-sicher, daher könnte eine einzige DB-Kontext-Instanz über mehrere Anfragen hinweg zu gleichzeitigen Problemen führen. Indem man pro Anfrage eine DbContext-Instanz verwendet, ist es leichter, Transaktionen zu verwalten und die Datenkonsistenz über eine einzige Arbeitseinheit sicherzustellen, ohne Störungen durch andere Anfragen. Und außerdem kann die Nutzung derselben DB-Kontextinstanz über einige Anfragen hinweg zu mehr Speicherbedarf führen, weil der Kontext Änderungen an Entitäten über seine Lebensdauer verfolgt. Durch die Verwendung einer Scoped-Lebensdauer bleibt jeder DB-Kontext kurzlebig, was Speicherbedarf reduziert und Leistung wirklich verbessert. Das sind doch die Hauptgründe, warum. Der DbContext ist mit einer Scoped-Lebensdauer registriert, und Sie sollten das beachten, wenn Sie den DbContext in Ihren APIs nutzen. Jetzt kehren wir in unsere Spiel-Endpunkte zurück. Und schau, wie man diesen TV-Kontext nutzt. Und zuerst hier tun. Es geht darum, eine neue Instanz zu erstellen, nicht von unserem Spiel, wie bisher, sondern von unserem neuen Spielmodell, das wir wirklich nutzen, um es in der Datenbank zu speichern. Also lass uns das hier alles löschen und stattdessen unser Spiel erstellen, indem wir Game Game einfach so machen. Und dafür lass uns hier einfach so vorgehen, damit wir unseren GameStore.API.Models-Namespace korrekt einführen können. Und das wird dort unsere neue, wirklich neue Instanz sein. Und hier wird die erste Eigenschaft, die festgelegt werden soll, tatsächlich unser ganz persönlicher Name sein. Also können wir den Namen auf 'new game' setzen. Gib bitte den Namen ein und achte darauf, dass wir die ID nicht angeben, denn der Datenbankanbieter wird dafür letztlich verantwortlich sein, wie eine eindeutige Kennung für das Spiel erzeugt wird, sobald das Spiel dort erstellt worden ist. Als Nächstes möchten wir unsere Generierungs-ID festlegen, die unser künftiges, neues Spiel wäre. Diese Generierungs-ID. Allerdings sieht man, dass wir in unserem Create-Game-DTO noch keine Generierungs-ID haben, oder? Es ist nur Generierung, und das müssen wir unbedingt ändern, damit das DTO vollständig wird. Wenn wir ins Create-Game-DTO zurückgehen, erinnern wir uns daran, wie wir unsere Generierung hier definieren, richtig? Und das klappt nicht so richtig. Wenn unsere Frontend-Kunden Schick POST an unseren Endpunkt Weil die eindeutige Kennung des Gewählten Generators das ist, was sie senden. Frontend-Oberfläche. Lass uns das ändern. Eine Identifikationsnummer erzeugen. Und in Bezug auf unsere Datenannotation ändern wir vielleicht alle davon in einen gültigen Bereich für unsere Generatoren. Von eins, zwei, sagen wir fünfzig, damit wir zumindest zu Beginn potenziell bis zu fünfzig Generatoren haben könnten. Und damit kehren wir zu den Gewinnpunkten zurück, zu jenen wichtigen, zukunftsorientierten Zielen, die uns klare Ergebnisse anzeigen und die Richtung deutlich vorgeben. Und jetzt können wir hier ein neues Spiel definieren, um eine eindeutig identifizierbare ID zu erzeugen, und wir fahren fort mit dem Preis dieses neuen Spiels, der festgelegt wird, damit alles konsistent bleibt. Und das Veröffentlichungsdatum des neuen Spiels ist der festgesetzte Termin, an dem es offiziell veröffentlicht wird. So definiert es uns. Das Spielmodell, das in die Datenbank eingefügt werden soll. Aber wie fügen wir es tatsächlich in die Datenbank ein? Nun, das läuft so, dass wir dafür unseren DB-Kontext verwenden müssen. Also statt dieses Vorgehens setzen wir künftig auf den DB-Kontext statt auf Spiele, die etwas hinzufügen. Und hier präsentieren wir unser neues Spielmodell. Äh. Beachten Sie jedoch, dass diese Zeile das Spiel nicht tatsächlich in die Datenbank sendet. Sie veranlasst lediglich Entity Framework Core, damit es beginnt, zu verfolgen, dass ein neues Spiel in die Datenbank eingefügt werden muss, um den DV-Aufruf auszuführen und das Spiel zu speichern. Was Sie tun möchten, ist Kontext dafür zu geben, dass Änderungen gespeichert werden. Dies übersetzt alle Gemäldenänderungen im DB-Kontext. Änderungstracker. In SQL-Anweisungen, die die Datenbank künftig verstehen wird. Also ist das Spiel damit gespeichert, aber natürlich müssen wir dem Client noch etwas zurückgeben. Und wie wir hier sehen können, befindet sich unsere Route-Methode 'created_at' hier. Sie enthält hier unsere Spielinstanz vollständig und sichtbar, hier drüben. Allerdings ist das zu diesem Zeitpunkt nicht ideal, denn daran erinnert man sich: Das hier gezeigte Spiel gehört nicht mehr zu ETO. Es ist unser tatsächliches Spielmodell, das gerade in der Datenbank gespeichert wurde. Und aus guten Gründen möchten wir die internen Details des Systems weder unseren Anrufern noch unseren Kunden offenlegen. Denn das würde es später erschweren, unser internes Datenmodell zu ändern, ohne unsere Kunden zu beeinträchtigen. Also statt unser Spielobjekt zurückzugeben, tun wir das. Gib erneut DTO zurück. Welche DTO sollen wir hier eigentlich verwenden? Nun, es könnte dasselbe sein, das wir vorher benutzt haben, also schauen wir kurz darauf. Gehen wir in die DTS, und jene war das Game-DTO. Das ist das, was wir zurückgegeben haben. Allerdings wird dieses hier nicht ganz funktionieren, denn wie man sehen kann, enthält es tatsächlich 'degenerate' als Zeichenkette, im Gegensatz zu einer Ganzzahl. Also statt dieses zu verwenden, lassen wir es vorerst einfach dort stehen und legen los, ein neues DTO zu erstellen. Ich kopiere das hier und füge es dort als Kopie ein. Und wir benennen dieses Neue als Game details, DTO. Okay, also das hier ist Game details, DTO. Lass mich das entfernen. Lass uns das zusammenlegen und hier die richtige Benennung vornehmen. Game Detail C#, TO. Und natürlich besteht der Unterschied darin, dass dieser hier etwas zurückgeben wird. Und ich werde eine ID generieren. Und jetzt, da wir das hier haben, können wir wieder in unsere Spiel-Endpunkte zurückkehren. Und nach unserem sicheren Änderungsaufruf können wir Spieldetails definieren. DTO, nennen wir es Game-DTO. Es wird ein neues DTO sein, okay. Lass uns bitte, gemeinsam, Klammern öffnen und wieder schließen. Und hier möchten wir ganz bewusst unsere Game-ID angeben. welches übrigens zu diesem Zeitpunkt nach Aufruf von Safe changes wird diese ID bereits den automatisch generierten Wert für die Spiel-ID haben. Es ist sinnvoll, jetzt die ID zu verwenden. Danach geben wir den vollständigen Namen unseres Spiels an. Generiere diesen Namen bitte jetzt. Das Spiel, dieser Preis betrifft das Ende des Spiels. Bitte gib außerdem das Veröffentlichungsdatum an. Dann kopieren wir diese Game-DTO-Instanz einfach erneut, und wir verwenden sie für unseren Aufruf der Route 'created_at'. Hier, bitte. Legen wir sie hierher, statt in das Spiel. Wir fügen sie außerdem als Payload dieser POST-Anfrage hinzu, äh, zur Rückgabe. Also verwenden wir sie hier direkt, Game-DTO, und zwar jeweils hier, bitte nochmals. Und damit ist unser POST-Endpunkt gänzlich darauf umgestellt worden, tatsächlich unseren DB-Kontext zu verwenden, um das Speichern von Spielen in der Datenbank zu starten. Es ist jetzt gut, das auszuprobieren. Öffnen wir doch unsere Terminals. Ich drücke hier Strg-J. Ich werde umschalten auf Und speichere API. Ich mache gleich einen Probelauf. Okay, lass uns das hier jetzt bitte für einen Moment einfach mal kurz schließen und danach unsere HTP-Datei für Spiele öffnen. Erinnern wir uns daran, dass hier unser POST-Aufruf vorhanden ist, richtig? Also hier ist der POST-Aufruf, um ein Spiel zu erstellen. Aber natürlich besteht das Problem darin, dass es bisher immer noch als String verwendet bzw. erzeugt wird. Also steht hier Platformer. Wie uns allen bekannt ist, ist das etwas, das wir nicht mehr tun können. Wir müssen die erzeugte ID liefern. Also sollte dies die erzeugte ID sein. Aber was ich hier so getan habe. Wir müssen das herausfinden, indem wir kurz in unsere DB schauen. Also klicken wir erneut auf Game Store-Dev. Wählt bitte eine offene Datenbank aus. Geht in unseren ES Light Explorer und klickt hier auf den Playknopf, um den Inhalt unserer Allgemeinen Tabelle zu sehen. Auf der rechten Seite sehen wir unsere aktuellen Generäle in der Datenbank. Dem Platformer-Generator ist wirklich die Nummer drei zugeordnet, richtig? Platformer ist Nummer drei. Lass uns diese Drei verwenden, um unser Spiel zu machen. Schließen wir das hier und setzen die Drei hier. Und jetzt bricht es kurz zusammen. Lasst uns hier auch unseren Preis ändern. Das ist zu teuer. Das. Jetzt senden wir eine Anfrage und schauen, ob wir das Spiel in die Datenbank aufnehmen können. Also klicken wir auf 'Anfrage senden' – und die Anfrage war erfolgreich. Wir können sehen, dass 201 erstellt wurde. Wir sehen. Hier unten wurde ein Spiel erzeugt. Und wichtig: wie ich schon sagte, sehen wir, dass eine eindeutige Kennung für unser Spiel von SQLite bereitgestellt wurde. Wir mussten sie nicht angeben. Es ist das Standardverhalten vieler Datenbanken, automatisch eine ID zu erzeugen. Zu Ihren Unterlagen, nach einer Sequenz. Nun möchten wir wirklich bestätigen, dass das Spiel in der Spieletabelle existiert. Also bitte schließen wir Strg-Shift-E. Ich kehre nun wirklich in unseren Escalate-Explorer zurück. Klicken wir hier bitte mal auf den Pfeil der Spieltabelle. Klicken wir dort, und wenn wir das kurz minimieren und dorthin verschieben, sehen wir, dass das Spiel in der Datenbank erstellt wurde. Unser Folgeanruf war tatsächlich ein echter Erfolg. Schließen wir das. Gehen wir zurück zu unseren Spiel-Endpunkten. und bevor wir beginnen, den Rest unserer Endpunkte im Game Store-Kontext zu nutzen, Ich. Es gibt noch ein weiteres Konzept, das wir lernen müssen, das ist das asynchrone Programmiermodell. Lass uns hier kurz pausieren. Mehr über Async-Programmierung lernen. Um asynchrone Programmierung zu verstehen, betrachten wir ein typisches Frühstücksszenario als Beispiel im Alltag. Nehmen wir an, du erhitzt deine Pfanne ein paar Minuten, und wenn sie heiß ist, brätst du dort Eier. Außerdem möchten wir zum Frühstück auch etwas Brot haben; nachdem die Eier fertig sind, holen wir den Toaster heraus und rösten das Toastbrot. Dann, wenn das Brot fertig ist, belegen wir es mit Marmelade oder Erdnussbutter. Schließlich wäre unser Frühstück ohne Saft nicht vollständig, also gießen wir etwas Orangensaft nach. Insgesamt hat es uns etwa dreißig Minuten gedauert, unser Frühstück zuzubereiten. Aber ist das wirklich so, wie du dein Frühstück an einem Werktag zubereiten würdest, wenn du oft in Eile bist, vielleicht würdest du dann das hier tun. Du erhitzt deine Pfanne, und währenddessen fängst du ebenfalls eben an, deinen Atem zu rösten. Und während das geschieht, kannst du vielleicht auch deinen Orangensaft einschenken. Schließlich, wenn die Pfanne bereit ist, gehst du zurück, um zu essen und deine Eier zu braten, und sobald das Brot geröstet ist, gehst du zurück und bestreichst es mit Marmelade oder Erdnussbutter。 Wenn du so vorgehst, bist du deutlich schneller fertig – sagen wir mal 15 Minuten –, und den Rest der Zeit kannst du dann dein Frühstück genießen. Wenn man diese beiden Arten vergleicht, wie man sein Frühstück zubereitet, sagen wir, dass der erste Ansatz synchron ist, da man keinen neuen Auftrag beginnt, bevor der vorherige abgeschlossen ist. Der zweite Ansatz hingegen ist asynchron, da man nicht darauf wartet, dass eine Aufgabe abgeschlossen ist, bevor man mit der nächsten beginnt. Hier beginnst du so viele Aufgaben, wie du kannst, und schließlich richtest du deine Aufmerksamkeit auf Aufgaben, die für dich bereitstehen, damit du mit der nächsten Aufgabe weitermachen kannst. Auf ähnliche Weise können Sie in ASP.NET Core-Anwendungen asynchrone Programmierung einsetzen. Wenn ein Client eine Anfrage an Ihren Webserver sendet, möchten Sie die Anfrage in Ihrem Endpunkt asynchron verarbeiten. Damit dein Code, der Webserver, sofort wirklich frei ist, mit der Bearbeitung der nächsten Anfrage zu beginnen. Wenn dein Endpunkt einen asynchronen Aufruf startet, etwa an deinen DB-Kontext, und dieser wiederum Daten asynchron aus der Datenbank anfordert, hat der Webserver bereits begonnen, die nächste Anfrage zu bedienen. Auch asynchron. Wenn die Datenbank schließlich die angeforderten Daten liefert, setzt der Kontext der Datenbank die Arbeit fort und sendet die Daten an den Endpunkt zurück, der dann die Arbeit fortführt, Objekte in Details umwandelt und die Daten an den Webserver zurücksendet, der auf die Clientanfrage der Region antwortet. Danach setzt die Anwendung das asynchrone Starten von Aufträgen fort und nimmt die Arbeit nun falls nötig wieder auf. Wie Sie sehen können, bringt das asynchrone Programmiermodell mehrere Vorteile. Ihre Anwendung erzielt eine bessere Leistung, da blockierende Aufrufe vermieden werden und Ressourcen freigegeben werden, damit sie andere Aufgaben übernehmen können, was zu einer insgesamt besseren Reaktionsfähigkeit führt. Sie können Ihre Anwendung besser skalieren, weil sie mehrere Anfragen und Benutzer gleichzeitig verarbeiten kann, ohne durch das Warten auf I/O-Operationen blockiert zu werden. Außerdem ermöglichen die Schlüsselwörter async und await eine einfache und intuitive Methode, asynchronen Code zu schreiben, statt sich direkt mit Threads und Callback-Funktionen herumschlagen zu müssen. Jetzt, da du das asynchrone Programmiermodell und seine Vorteile verstehst, schauen wir uns an, wie man es in unserer ASP.NET Core-Anwendung einsetzen kann. Eine Sache, die wir wirklich verstehen müssen, bezüglich der Art und Weise, wie wir unsere API-Endpunkte implementiert haben, insbesondere unseren POST-Endpunkt hier, ist, dass zu jeder gegebenen Zeit genau ein einzelner Thread für die Ausführung dieses Endpunkts zugewiesen wird, richtig? Also läuft alles, was in diesem Endpunkt programmiert oder codiert ist, in exakt einem Thread ab. Und wenn Sie es so ausführen, ist das der synchrone Weg, den Code auszuführen. Dieser Thread kann nie an die Laufzeitumgebung zurückgegeben werden, damit diese nichts anderes tun kann, oder doch? Die Laufzeit ist darauf festgelegt, dass wir den Code vollständig abschließen, bevor diese Ressource zurückgegeben wird. Deshalb wechseln wir zum asynchronen Programmiermodell. Damit wir nur so viel Arbeit erledigen, wie nötig. Und wir haben alle Ressourcen wieder in die Laufzeit zurückgegeben, damit sie etwas damit anfangen können, bis wir bereit sind, mit unserem Code weiterkommen. In dieser Methode schauen wir auf Zeile 60, wo wir Safe Changes aufrufen. Dies ist die Zeile, in der wir mit der Datenbank sprechen. Alle SQL-Befehle, die nötig sind, um unser Spiel zu speichern. Dies ist eine Lage, in der wir aus unserem Prozess aussteigen und auf eine externe Ressource – die Datenbank – zugreifen müssen, die möglicherweise Zeit braucht, um zu antworten. Die lokale Box ist etwas schneller, doch in der Produktion könnte eine Cloud-Datenbank gehostet sein, was Zeit kostet. Solange das passiert, können die Ressourcen dieser Bedrohung nicht in die Laufzeit zurückgeführt werden. Daher schalten wir auf das asynchrone Ausführungsmodell um, um Ressourcen freizugeben. Beachten Sie nun die Rückgabe der Änderungen. Derzeit gibt es nur eine Ganzzahl zurück, die die Anzahl der Datensätze beschreibt, die in der Datenbank gespeichert wird. Und was du bei vielen Methoden wie dieser merkst, ist, dass es meist eine asynchrone Version der Methode gibt, wie diese hier zum Beispiel; sie ändert sich asynchron. Das wird nicht mehr nur eine Zahl zurückgeben, sondern eine andere: eine Aufgabe, richtig? Eine Aufgabe vom Typ in diesem Fall. Das öffnet die Tür dazu, damit nicht nur eine synchrone Nummer zu empfangen. Eine Aufgabe, der man Gewicht geben kann, und die nach Abschluss weitere Arbeit zulässt. Nun, da dies jetzt eine Aufgabe zurückgibt, können wir den Rest des Codes nicht einfach ausführen, wie er jetzt ist. Denn wenn Sie diese Methode aufrufen, Du wartest nicht mehr darauf, dass in diesem Vorgehen alles fertig wird. Du bittest sie nur darum. Fang mit der Arbeit an; die Aufgabe kommt sofort zurück, und der Code läuft weiter. Und wenn du nicht wartest, bedeutet das, dass dieser Code schon läuft und sogar ein Ergebnis liefert, bevor Änderungen in der Datenbank gespeichert sind. Also gibt es eine Möglichkeit, damit umzugehen, zum Beispiel; es gibt mehrere Wege, aber eine davon ist die, dass du das tun könntest und damit fortzufahren. Und dann könntest du hier einen Ausdruck öffnen, der die Aufgabe entgegennimmt, und hier einen Lambda-Ausdruck öffnen, in dem du tatsächlich den Code schreibst, um deine Logik weiterzuführen. Richtig? Die Logik, die wir hier haben, auf die ich nicht eingehen werde; mach nichts Kompliziertes. Das ist eine Art zu sagen: Hey, leg los. Änderungen speichern und alle sicheren Änderungen. Die Schritte sind erledigt. Bitte kommen Sie zurück, dann erledigen wir den Rest des Codes. Und in dem Zeitraum, Die Ressourcen unseres Endpunkts werden an die Donnet-Laufzeit zurückgegeben, und sie kommen wieder, sobald wir weiterfahren. Jetzt könnten wir es so machen, aber das ist wirklich eine ältere Art, Aufgaben zu erledigen. Es gibt eine viel bessere Syntax, die die Schlüsselwörter async und await verwendet. Also lasse ich das auf diese andere Signatur zurück. Was wir ausdrücken möchten, ist, dass wir auf diese Ausführung wirklich warten möchten, richtig? Wir wollen auf die Ausführung der Aufgabe warten, aber damit das funktioniert, müssen wir es auch mit dem Async-Schlüsselwort kombinieren. Also, wenn wir hier auch ganz nach oben gehen. Zu Beginn unseres Handlers soll hier das Async-Schlüsselwort endlich eingeführt werden. Damit sagen wir dem Compiler, dass wir nicht nur einen Aufruf an eine asynchrone Methode machen wollen, 'changes async', sondern dass der Endpunkt asynchron laufen soll. Das bedeutet, dass wir dem Compiler zum falschen Zeitpunkt sagen, dass hier asynchroner Code läuft. damit es bereit ist, Ressourcen freizugeben, falls wir asynchrone Änderungen durchführen müssen, was Zeit kostet. In dieser Zeit soll die Laufzeit etwas anderes tun, bevor die Kontrolle an unsere Methode zurückkehrt, damit wir hier die Logik fortführen können. Als Best Practice suchen Sie auch die asynchrone Version Ihrer Methoden – wie diese hier. Änderungen erfolgen asynchron; nutzen Sie async und await, um sie zu kennzeichnen. die Tatsache, dass du Dinge asynchron ausführst. Da unser POST-Endpunkt jetzt bereit ist, nehmen wir hier auch die Änderungen an unserem Get-Endpunkt zur Abfrage nach ID vor, damit er ebenfalls unseren DB-Kontext verwenden kann und er außerdem asynchron arbeitet. Also fangen wir damit an, unseren Datenbankkontext hier als weiteren Parameter des Game Store einzuführen, damit er über Abhängigkeitsinjektion empfangen wird. Lassen wir uns hier am Anfang den Async-Modifikator einführen. Und dann sind wir vollständig bereit, dieses Spiel aus der Datenbank abzurufen. Also statt dies zu tun, was wir gerade tun würden, folgt Folgendes: Wir werden 'await' sagen. Im Kontext, dass Spiele asynchron gefunden werden, und dann geben wir die Idee des Spiels an. Der Rest der Logik wird ähnlich sein, oder? Ist das Spiel neu, bedeutet es, es steht nicht in der Datenbank. Kehren wir zurück; es wird nicht gefunden. Wir haben das Spiel gefunden und sind bereit, Antwort zu senden. Doch bleibt das Problem wie vorher mit dieser Antwort, denn dieses Objekt ist eine interne Darstellung. Zu unseren Spielen in der Datenbank wollen wir die interne Darstellung nicht zurückgeben. Wir liefern das DTO zurück. Also lass uns das hier vollständig entfernen und stattdessen ein neues Spiel zurückbringen. Details-DTO-Objekt, welches unsere Spiel-ID empfängt. Dieser Spielname soll eine eindeutige ID erzeugen. Ziel ist der Preis und das Spiel, sowie das Veröffentlichungsdatum. Und das sollte gut genug sein, damit unser Get-by-ID-Endpunkt die Spiele aus der Datenbank abrufen kann. Also probieren wir das mal aus. Öffnen wir unser Terminal. Lass uns einen Probelauf durchführen. Okay, lass uns das hier schließen. Gehen wir in unsere Spiel-Datei unter games dot http-Datei. Und wir haben bereits ein Spiel erstellt, richtig? Wir haben dieses Spiel schon erstellt, also sollte es in der Datenbank eine ID 1 geben. Dann aktualisieren wir hier unseren zweiten Endpunkt mit der Nummer Eins. Klicke bitte auf Sendeanfrage. Und wie erwartet können wir dieses Spiel jetzt empfangen. Wir haben 200, okay? Und hier unten haben wir den Spielkörper mit der erwarteten Antwort. Also haben wir jetzt die Möglichkeit, Spiele zu erstellen und ein Spiel abzurufen. Aber ID aus DB – nicht nur EF Core, sondern asynchron. Schauen wir, wie wir den API-Endpunkt aktualisieren, der alle unsere Spiele abrufen kann. Der Endpunkt, der diese erste Anfrage beantwortet, ist dort. Ich öffne das Terminal und stoppe meinen Server. Wir kehren zu den Spiel-Endpunkten zurück. Der Endpunkt, den wir ändern wollen, ist dieser hier. Also wie üblich beginnen wir damit, unseren Kontext für das Spielgeschäft vorzustellen – hier der Kontext, Abhängigkeitsinjektion. Dann machen wir unsere Methode asynchron, indem wir hier async verwenden. Und dann werden wir diesen Ausdruck aktualisieren, ich meine den Handler, den wir hier definiert haben, damit er nicht mehr Spiele zurückgibt, sondern stattdessen Folgendes tun wird. Es wird nun eine Gewichtung des DB-Kontexts vorgenommen. Spiele, Und von dort aus werden wir projizieren. Die Bausteine, die der Kunde erhält. Wir wollen nicht die Spiele selbst zurückgeben, denn doch wie gesagt wollen wir Details dazu nicht preisgeben, wie wir Spiele in der DB speichern. Wir liefern die DTO-Version dieser Objekte zurück; dazu reicht eine SELECT-Abfrage. Und hier werden wir unser gegenwärtiges Spiel hier in ein völlig neues Spiel projizieren, das DTO genannt wird. Jetzt öffnen wir hier unsere Klammer. Und wir müssen damit beginnen, unsere Werte bereitzustellen, richtig? Also werden wir unsere game.id, unsere game.name angeben, und im Fall dieses speziellen DTOs möchten wir bitte String-Version unseres Game-Generates statt der Generate-ID angeben. Und das liegt daran, dass wir erwarten, dass das Frontend, das diese Methode aufruft, sich nicht um konkrete Ideen zum Spiel Generous kümmert, sondern lediglich eine String-Version genügt. Wie bekommen wir nun die generierte ID? Folgendes: Wir können game.generate.name verwenden, um auf die zusammengesetzte Eigenschaft zuzugreifen. Beachte, dass generate hier vom Typ Generate ist, und von dieser Eigenschaft aus können wir den Namen abrufen. Jetzt sehen wir hier eine Warnung. Es gibt eine Warnung zur Erkennbarkeit von Degeneriertem. Das passiert, weil wir Degeneriertes als erkennbar deklarieren; der Compiler sorgt, dass wir etwas verwenden, das neu sein könnte. Es ist legitim, Degeneriertes auch mal neu zu verwenden; wie gesehen, braucht man es nicht immer. Das erzeugt eine zusammengesetzte Eigenschaft. Zum Beispiel hier in unserem Endpunkt zum Abruf nach der ID verwenden wir nur die Generierungs-ID, und wenn wir im POST-Endpunkt hier eine neue Instanz des Spiels erstellen, verwenden wir erneut nur Generierungs-ID, denn das genügt, um den Fremdschlüssel zu erfüllen, richtig? Es gibt jedoch Fälle wie diesen hier, in denen wir auf diese Eigenschaft zugreifen möchten und anschließend auf die Eigenschaften innerhalb dieser zusammengesetzten Eigenschaft zugreifen können. Nun gibt es hier zwei Dinge, die wir erledigen müssen. Das erste ist, Entity Framework Core zu bitten, das Generierte auch aus der Datenbank zu laden, sobald die Abfrage gesendet wird. Zur Eskalation dieses Falls. Wenn wir das nicht tun, erscheint das Generierte dort als neuer Wert, und dann stürzt es hier ab. Um Entitäten in Entity Framework Core zu laden, macht man Folgendes: Man fügt einfach Include hinzu und gibt dann an, was in der Antwort aus der Datenbank enthalten sein soll. In diesem Fall wird es generiert werden. Also wird EF Core es als Teil der Antwort einschließen, die wir erhalten werden. Auf diese Weise werden nur die relevanten Beziehungen geladen. Jetzt versteht der Compiler nicht einfach, dass wir hier durch dieses Include sicher nen Wert bekommen; er meckert weiter. Das ist einer jener Fälle, in denen man das Verhalten übernehmen und dem Compiler sagen kann, dass man sich nicht kümmert, was er davon hält. Was könnte hier passieren. Wir wissen, dass das Allgemeine in diesem Fall unbekannt bleiben sollte. Deshalb können wir den neuen fehlerverzeihenden Operator verwenden – das Ausrufezeichen, das Sie hier sehen –, wir verwenden ihn, um dem Compiler mitzuteilen, dass er sich keine Sorgen machen muss, weil wir wissen, dass das Allgemeine mit einem Wert versehen sein sollte. Okay, also lass uns jetzt einfach die hier benötigten Merkmale abschließen. Wir müssen den Preis unseres Spiels und das Release-Datum unseres Spiels angeben. Jetzt meckert der Compiler hier mit diesen roten Wellenlinien, weil. Die Rückgabe dieser Abfrage hier ist nicht asynchron. Also müssen wir diese Antwort in eine echte asynchrone Antwort verwandeln, etwas, das die Aufgabe wirklich zurückgibt. Und dazu können wir einfach wirklich ganz direkt nach unserem Select-Aufruf hier Folgendes tun, damit der Prozess fortgesetzt werden kann. Bei Align machen wir das so, um Async aufzulisten, indem wir aus dieser Linkabfrage hier eine wirklich angemessene Antwort nehmen und sie in eine Aufgabe verwandeln, die eine Liste von Spiel-DTOs ergibt. Und das sollte funktionieren. Eine gute Praxis hier ist, EF Core zu bitten, die zurückkehrenden Ergebnisse nicht zu verfolgen. Standardmäßig will es alle dieser Entitäten verfolgen, falls du Änderungen an ihnen vornehmen und sie in die Datenbank zurückspeichern willst. Wie Sie sehen, besteht alles, was wir tun, darin, einfach mit der Datenbank zu sprechen und die Werte zu liefern. Es gibt hier keine weitere Logik. Sehr einfach. Um hier Leistung zu erhöhen und zu fragen, ob Core diese Entitäten nicht verfolgen soll, müssen Sie einfach sagen: Kein Tracking. Und jetzt wird der EF Core-Tracker für diese Antwort abgeschaltet, und die Abfrage wird im Wesentlichen schneller sein. Bevor wir das hier testen, noch eine Sache: Wir sollten unseren Game-DTO hier umbenennen, denn jetzt haben wir Spiel-Details, C#, TO und dieses DTO. Dann kläre ich, worum es bei dem DTO geht. Also nehmen wir das Contra-Shift-Team, um unseren Datei-Explorer zu öffnen. Lass uns ins Spiel-DTO gehen. Und was ich gerne tun würde, ist einfach, das Game-DTO in ein Game-Zusammenfassungs-DTO umzubenennen. Das wird der neue Name sein: Game-Zusammenfassungs-DTO für die Datei. Und für den eigentlichen Datensatztyp werde ich F zwei verwenden und hier Game einsetzen. Also Eingabe. Okay, zurück zu den Gains-Endpunkten. Wir sollten hier und auch an anderer Stelle in dieser Datei erkennen können, dass der neue Name verwendet wird. Jetzt probieren wir das aus. Also öffnen wir jetzt das R-Terminal, Strg-J. Ich starte jetzt meinen Server. Ich. Okay, lass uns das hier schließen. Wir gehen zurück zu unserer Games-Datei, damit unsere Antwort interessanter wird, und wir sollten mindestens ein weiteres Spiel hinzufügen, damit wir mehrere sehen können, ja, bitte? Also habe ich eine weitere Nutzlast für unsere POST-Methode vorbereitet, die ich hier einfügen werde. Also ist das jetzt drei Kämpfer, zwei davon mit Erzeuge Eins, was unsere Kampf-Generierung sein sollte. Hier der Preis und das Datum. Also, lass uns jetzt die Anfrage absenden. Okay, also wurde das Spiel erstellt, richtig? Es wurde erfolgreich erstellt. Hier sehen wir, dass die ID-Nummer zwei und Januar eins zugewiesen wurden. Also können wir jetzt unseren Endpunkt Alle Spiele abrufen testen, der erste in unserer Datei. Lass uns jetzt auf Anfrage senden klicken. und wir sehen, dass dort eine erfolgreiche Antwort eingegangen ist. 200. Okay. Und wir sehen die Antwort der Methode, die jetzt beide unsere Spiele zurückbringt, richtig? Also hier haben wir Super Mario Overdose Wonder und unser Three Fighter 2-Spiel. Beachten Sie, dass selbst dann, wenn die Generatoren in der Spieletabelle als IDs gespeichert sind, wir hier die eigentliche Zeichenfolge des Generators extrahieren konnten – sowohl für Super Mario Bros hier als auch für Three Fighter Two. Jetzt fahren wir mit unserem folgenden Endpunkt fort, der ganz sicher der PUT-Endpunkt sein wird. Also Lass uns unseren Server stoppen. Lass uns das hier schließen. Lass uns doch zu den Spiel-Endpunkten zurückgehen, und nach unserem suchen. Karte, schieb den Anruf hierhin. Wie üblich. Lass uns unseren Spieleladen-Kontext vorstellen. Dort drüben ist unser DB-Kontext. Vielleicht schicke ich die Dinge zur nächsten Folie, damit wir sie besser sehen. Die Bezeichnung 'Signatory' ist doch etwas lang. Danach werden wir die Methode asynchron gestalten, indem wir hier, wie es üblicherweise der Fall ist, das Async-Schlüsselwort einführen, in der Praxis. Bezüglich der Umsetzung werden wir das nicht mehr tun, und stattdessen führen wir Folgendes aus. Wir werden es mit 'we bar' erledigen. Das vorhandene Spiel wird zu einem Gewicht im Gesamtkontext werden, der Spiele betrifft, die Async verwenden, in dieser Hinsicht. Und wir geben unsere ID. So finden wir das Spiel. Aber natürlich kann es schon sein, dass wir das Spiel nicht finden. Dann wäre das vorhandene Spiel neu. Und in dem Fall müssen wir tun, was wir hier schon versucht haben. Was wir in diesem Fall tun. Es dient lediglich dazu, zu prüfen, ob das vorhandene Spiel wirklich neu ist. Wir liefern weiter Resultate, die nicht gefunden sind. Dann geht's weiter. Wir aktualisieren das Spiel, das wir gefunden haben. Es muss nun mit den neuen Eigenschaften der eingehenden Daten aktualisiert werden. Also tun wir das. Der bereits vorhandene Spielname lautet derzeit aktuell Updated Game. Nenne den Namen bitte. Die vorhandene Spiel-ID wird derzeit sehr zügig aktualisiert. Bitte tu es jetzt sofort. Idealerweise generieren wir eine ID, aber wie man sieht, steht die generierte ID im aktualisierten KDTO nicht zur Verfügung, ähnlich dem, was mit unserem POST-Endpunkt passiert ist. Also lasse ich hier einfach F12 drücken, um zu unserem DTO zu gelangen, und dies ist der Moment, dieselbe Änderung vorzunehmen, die wir mit unserem gemacht haben. Erstelle hier ein Game-DTO mit der Generate-Funktion. Vielleicht schauen wir kurz auf unser Create-DTO, damit wir dieselbe Eigenschaft mit gleichen Beschränkungen übernehmen, die wir bisher festgelegt haben. Okay. Das beende ich hier. Ich kehre zurück, um das Game-DTO zu updaten, und ich schalte es auf ID-Generierung mit einem Bereich von eins bis fünfzig um. Damit kehren wir zu den Endpunkten des Gewinns zurück und nutzen unsere neue ID-Eigenschaft. Nun lasst uns dies abschließen, indem wir das bestehende Spiel bearbeiten. Der Preis wurde aktualisiert, das Spiel, dieser Preis, und schließlich die Veröffentlichung des bestehenden Spiels. Das Datum wurde aktualisiert. Bitte geben Sie das Veröffentlichungsdatum des Spiels an. Und das Letzte, was wir hier tun müssen, ist, Core zu bitten, diese Updates in die Datenbank zu senden. Dafür bleibt uns nichts anderes übrig, als geduldig abzuwarten, dass der Kontext sichere Änderungen ermöglicht. Noch einmal, ich. Und das ist alles, was wir tun. Um unseren Endpunkt für Updates in die Datenbank vorzubereiten. Jetzt testen wir es. Dann starten wir Server neu. Ich starte ihn hier. Okay, lass uns dieses Terminal schließen. Kehren wir zu den Gangs bei HGTP zurück. Und dann ist das Vorgehen, das wir dieses Mal nutzen, hier: unsere PUT-Anfrage. Bevor wir Änderungen vornehmen, erinnern wir uns kurz daran, wofür wir unser strenges Fighter-2-Spiel erstellen, nämlich den Inhalt unserer POST-Anfrage. Also kopiere ich hier wirklich unseren POST-Body hinein. Bitte nutze ihn als Grundlage für unsere PUT-Anfrage. Den hier werde ich jetzt einfügen. Stellen wir sicher, dass wir die ID des Spiels aktualisieren, richtig? Also, das ist wirklich nicht Spiel Eins; dieses hier wird ganz sicher Spiel Zwei sein, oder nicht wahr? Das ist ganz klar Three Fighter Two. Und na ja, beim eigentlichen Update machen wir es so, dass es Strikt Fighter Zwei Turbo sein wird, und der Preis diesmal wird einfach deutlich teurer sein, oder nicht? 1999. Nun lass uns bitte eine Anfrage senden. Also sende bitte die Anfrage. Wir haben den Status 204 No Content sofort erhalten, was bedeutet, dass es gelungen ist. Alles gut, wirklich. Und ähm, nun bestätigen wir einfach, dass das Update erfolgt ist, indem wir zum Get-By-ID-Endpunkt zurückkehren. Dieses hier. Lassen wir Nummer zwei verwenden. Klicken wir darauf und senden die Anfrage. Und wie erwartet erhalten wir ganz sicher den Namen 'C# Fighter zwei Turbo' und den Preis. War das Update. Nun wechseln wir zum letzten Endpunkt, dem Lösch-Endpunkt. Also schließen wir das bitte. Lass mich den Server stoppen und zu den Spiele-Endpunkten wechseln. Wir schauen uns jetzt hier doch unseren Lösch-Endpunkt an. Und wie üblich können wir damit beginnen, unseren Spielstore gründlich und auch detailliert vorzustellen. Kontext-Datenbank-Kontext. Wir machen die Methode asynchron. Und um das Spiel dauerhaft aus der Datenbank zu entfernen, gibt es einige Möglichkeiten, doch meines Erachtens ist die effizienteste davon die nachfolgend beschriebene Vorgehensweise. Wir werden in diesem Zusammenhang den DbContext für Games verwenden. Anschließend bedienen wir uns der WHERE-Klausel, um die passenden Datensätze zu filtern. Wir sagen dann eindeutig, dass game.id gleich id ist. Also filtert das sämtliche Spiele, bis wir ein bestimmtes Spiel finden, das wir löschen möchten. Von dort aus können wir hier eben die wirklich asynchrone Delete-Methode ausführen. Welche ist diejenige, die noch genau diese Löschung aus der Datenbank auslöst? Dieses Muster hier, das ich nutze, ist das, was man als Massenlöschung bezeichnet. So löscht es alle Spiele, die diesem hier angegebenen Filter entsprechen. Nicht der einzige Weg, doch er ist wirklich sehr effizient, weil er nur einen DB-Zugriff braucht, um die Löschung durchzuführen, falls er das Spiel findet. Nur damit Sie es verstehen: In dem Fall gibt es keinen sicheren Änderungsaufruf, oder? Also keinen sicheren Änderungsaufruf, weil alles sofort geschieht, oder? Nur ein Aufruf an eine DB, der die Löschung ausführt; dann ist das Spiel verschwunden, falls es jemals gab. Okay, also probieren wir das mal aus, indem wir unseren Server noch einmal starten. Okay, ich schließe das hier. Geh zurück zu games dot http und teste diese, da ich keines meiner Spiele wirklich verlieren möchte. Ich füge einfach ein Testspiel hinzu. Nennen wir es einfach Testspiel. Okay? Die restlichen Details spielen keine Rolle. Ich klicke auf Anfragen zum Posten. Okay, das Spiel wurde erstellt, und es ist Spiel Nummer Drei. Es handelt sich um Spiel Nummer Drei. Wir können dort den Standort von Spiel Nummer Drei sehen. Bestätigen wir, dass das Spiel in der Datenbank vorhanden ist, indem wir unsere zweite Anfrage verwenden. Finden wir dieses Spiel jetzt. Ja, es ist dort. Also löschen wir es jetzt, indem wir zum letzten Endpunkt hier gehen, unseren Lösch-Endpunkt. Wir machen das ja für Spiel Nummer drei. Lass uns auf Senden klicken. Wir bekommen eine 204 No Content-Antwort, was bedeutet, dass dies erfolgreich war; das Spiel wurde gelöscht. Und das bestätigen wir, indem wir erneut den ID-Abruf für Namen Nummer drei aufrufen, damit wir sicher gehen. Lass uns erneut auf Senden klicken. Natürlich bekommen wir 404 – nicht gefunden – das Spiel ist jetzt verschwunden. Damit ist die Implementierung unserer Spiele-API abgeschlossen. Äh, aber bevor wir zum Nächsten übergehen, schauen wir uns einfach unsere Spiele-Endpunkte an. Und denkt daran, auch den Anfang dieser Datei zu bereinigen, denn dieses Spiel-Array ist jetzt völlig nutzlos. Also können wir jetzt einfach alles auswählen, okay. Und lösche es. Behalte nur die Endpunkt-Definitionen, die sich auf die Datenbank beziehen. Unsere Spiel-API ist vollständig. An diesem Punkt haben wir alle Endpunkte unserer Spiele-API abgeschlossen. Wir brauchen jedoch einen weiteren Endpunkt, nicht für Spiele, sondern für Spielgeneratoren, weil das Frontend eine Möglichkeit braucht, diese in der Benutzeroberfläche anzuzeigen. Die Liste aller verfügbaren Spielgeneratoren lässt dem Benutzer die Auswahl eines davon zu. Im Fenster zur Spieleerstellung. Nutze alles, was wir in diesem Kurs gelernt haben. Um rasch einen neuen Endpunkt zu bauen, der alle Datensätze abrufen kann. Lasst uns zuerst den Lösungs-Explorer öffnen. Lasst uns das hier bitte zuklappen. Gehen wir hier in unser Projekt hinein. Gehen wir in DTS, klicken mit der rechten Maustaste und fügen eine neue Datei hinzu, die vom Typ 'Record' ist, und benennen wir diese 're DTO'. Öffnen wir sie. Wir entfernen hier den Klassenmodifikator, und dies wird ein sehr einfaches Datentransferobjekt sein, das nur eine ID für den eindeutigen Bezeichner der Entität hat und dann noch einen Namen als Zeichenkette. Dies ist das DTO, das für die Antwort unseres neuen Endpunkts verwendet wird, der alle dieser Spieleadressen abrufen wird. Jetzt setzen wir den eigentlichen Endpunkt schrittweise um. Gehen wir nun wieder in unseren Solution Explorer, und navigieren diesmal in den Endpunkte-Ordner. Lasst uns bitte mit der rechten Maustaste auf Neue Datei klicken. Das wird eine Klasse sein. Nennen wir sie Jes Endpoints. Lasst uns hier mal öffnen. Zuklappen. Entfernen wir den überflüssigen Leerraum. Diese Klasse muss statisch sein, weil sie statische Methoden hat, die als Erweiterungsmethoden dienen. Wir deklarieren diese Methode. Sie wird öffentlich statisch sein. Nichts. Eine großzügige, breit angelegte Karte und mehrere Punkte, die dazu beitragen werden, unsere Web-Allokations-App deutlich zu erweitern. Wir werden unsere Routengruppe definieren, deshalb setzen wir Bar-Gruppe als App fest. Das ist unsere Karten-Gruppe. Der Wurzelpfad dieser Gruppe ist einfach großzügig; hier gibt es nur einen Endpunkt. Eine Gruppe zu haben und alle Endpunkte dieser Gruppe anzuhängen, folgt auch dieser Konvention. Und tatsächlich ist der Endpunkt, den wir hier äußerst präzise definieren möchten, ein GET-Endpunkt, der auf einen Aufruf an generous reagieren wird. Dazu setzen wir die Gruppe group.app ein. Wir werden wirklich in die Hood-Route hineinwechseln, direkt unter res. Dann legen wir hier unseren asynchronen Handler; er wird asynchron. Es empfängt unseren Game-Store-Kontext. D-Kontext. Stellen Sie sicher, dass wir C#-Steuerung verwenden, damit wir die King Store API-Daten verwenden können. Und dann verweist dies auf die nachfolgende Implementierung. Vielleicht. Wir schließen es vorerst. Hier möchten wir asynchron auf den DB-Kontext zugreifen. Großzügig gedacht, und wir werden das entsprechend projektieren. Also werden wir auswählen, neu generieren und ein DTO erzeugen, was wir in dieser Aufgabe zu tun haben. Um dieses API bzw. DTOs zu verwenden, setzen wir in C# einen Controller ein, um es sicher zu speichern und später abzulegen. Und für das generierte DTO geben wir D zurück, erzeugen eine eindeutig identifizierbare ID, und Gen bleibt dabei. Name Wir werden EF Core bitten, diese Daten nicht zu verfolgen, weil wir sie in keiner Hinsicht verändern möchten. Auch keinerlei Art der Nachverfolgung. Und schließlich wandeln wir das in eine Liste um, synchron, was unseren asynchronen Aufruf letztlich vollständig abschließt. Also ja, das ist so ziemlich alles. Das ist unsere Definition von unserem Endpunkt dort. Und natürlich müssen wir jetzt auch wieder in unser File-Explorer-Programm Cs gehen. Und vielleicht hier, nach unserem Map-Games-Endpunkt-Aufruf, können wir einen Aufruf an App Map Generous Endpoints machen. Und Na ja, das ist so ziemlich alles. Unser neuer Endpunkt ist ja bereit und wir können ihn gleich ausprobieren. Drück hier Strg-J, damit unser Terminal startet. Gehen wir in die Game-Store-API, machen es, tun es, führen es aus. Okay, es läuft entgegen der Verschiebung E. Gehen wir in Gains HT TP; das muss verloren gehen. Und was ich tun werde: Lass uns einfach bis zum Ende gehen, um hier noch eine weitere Anforderung einzuführen. Also drei Rautezeichen; der Host-Import wird derselbe sein. Also kopiere ich den Host und das Portal aus dem Löschaufruf genau dort hinein. Hier setzen wir einfach 'großzügig' hinein. Klicken wir jetzt auf 'Anfrage absenden'. Und auf der rechten Seite sehen wir, dass wir den erwarteten Status 200 erhalten haben. Okay. Es war ein Erfolg. Und hier sehen wir die ganze Liste aller Spiele, die wir in der Datenbank gespeichert haben. Unser Backend-API ist vollständig und einsatzbereit für die Integration in die Frontend-Anwendung. Auch wenn dieser Kurs ASP.NET Core behandelt, sehe ich, wie die API, die wir im Kursverlauf erstellen, eine wirklich echte hochmoderne Benutzererfahrung ermöglicht. Dafür habe ich eine kleine React-App vorbereitet, die mit unserer NET-API spricht. Nun zeige ich dir heute in diesem Lehrgang, wie du diese Anwendung hier so konfigurierst, dass sie mit der von uns erstellten API kommuniziert. Wie Sie sehen können, habe ich hier einen neuen Leiter, GameStore, der React heißt, jetzt. Dies ist die React-App, und wenn wir hier öffnen, werden wir eine Menge Dateien finden, aber die Hauptdatei, die wir uns schnell ansehen möchten, ist vite.config. Dies ist die Datei, in der wir die Konfig festlegen. Für die lokale Ausführung der Anwendung in diesem Fall verwenden wir den Bit-Server hier wirklich. Die Art und Weise, wie die Dinge eingerichtet sind. Jedes Mal, wenn irgendeine der Komponenten dieser Anwendung mit dem Backend kommunizieren muss, wird sie den Slash-API-Standort aufrufen, der über diese Proxy-Konfiguration auf unsere Backend-URL verweist. Nun, wo befindet sich unsere Backend-URL? Nun, merken wir uns das schnell. Wenn wir Strg+Umschalt+E öffnen, unseren Explorer, gehen wir in unseren Game Store, API-Eigenschaften, Launch-Serie und Jason. Und denk daran, dass wir hier unser HTTP-Profil haben, in dem wir die Anwendungs-URL für die lokale Entwicklung festlegen. Also werde ich einfach diese Anwendungs-URL kopieren, diese URL kopieren, Strg-A, Umschalt-E drücken. Lassen Sie uns dann in diese Config.ts zurückgehen, dort diesen Speicherort einfügen. Und damit sind wir bereit, die vollständige Full-Stack-Anwendung in Aktion zu sehen. Also Ich drücke Strg-J, um Terminal zu öffnen. Vielleicht vergrößere ich das Terminal. Ich starte zuerst unsere Server-App. Also startet unser Spiel per API. Ich führe net run aus. Und dann benutze ich hier diesen Plus-Button, um ein weiteres Terminal zu öffnen, das von ihnen verwendet wird, um die React-Anwendung zu starten. Also gehe ich jetzt in Game Store, React, Und da dieses hier auf Node.js basiert, muss ich daher NPM Round Dev zudem noch jetzt durchführen. Eine Anwendung ist bereits gestartet. Wir können hier die lokale URL der App sehen, die ich auf localhost:5173 kopieren werde, und hier in meinem Browser füge ich die Zuordnung ein. Dort wurde es eingegeben. Und hier sind wir in unserer Anwendung. Wie Sie sehen können, wurde die Startseite unmittelbar geladen. Die beiden Spiele, die wir zuvor erstellt hatten. über REST-Client in VS Code. Um nun zu bestätigen, dass diese Anwendung wirklich mit unserem Backend spricht, können wir hier ganz einfach F zwölf drücken, um die Browser-Entwicklertools zu laden. Und wenn wir hier in die Netzwerk-App gehen, hier ist sie. Wir öffnen jetzt diesen Teil, in dem wir ja alle Rufe sehen, die das Frontend an das Backend sendet. Ich aktualisiere es hier wirklich einfach jetzt. Ich sehe hier rechts mehrere Rufe, die alle Aktionen und Dinge zeigen, die das Frontend beim Laden durchführt. Nun ist hier viel los, also werde ich einfach filtern. Ja, dieser Button, ich filter nur die Aufrufe, die nach außen gehen und in unser Backend gelangen. Dafür klicke ich hier bei fetch/xhr. Ja, das wird dann nur die Fetch-Aufrufe offenlegen, bei denen Fetch die API in JS ist, die du verwenden kannst, um mit externem Dienst zu kommunizieren. Also hier sehen wir tatsächlich, dass wir mehrere Fetch-Aufrufe haben, die alle hier sichtbar sind. Klicken wir bitte auch auf einen davon. Wenn wir das weiter erweitern, sehen wir hier klar unsere Anfrage, die URL, die in den Pfad /api/games/location führt. Nun, wie kommt das in unsere Backend-API hinein? Denn die API existiert nicht in 51, 73; so funktionieren diese Dinge jedoch. Wie ich schon sagte, kehrt es zu VS Code zurück. Wenn wir uns unsere config.ts rechts ansehen, lass mich das mal zusammenklappen; das Frontend ruft die Slash-API auf, und dann wird die Slash-API auf unseren eigentlichen Speicherort übersetzt, wobei der API-Teil der Slash-API entfernt wird, und dann sind wir nur noch. Ich werde den Rest des Pfades aufrufen, und der Rest dieses Pfades wird nur Slash-Spiele sein, was Endpunkt der Netz-API. Jetzt gehen wir in unsere UI und klicken einfach auf Neues Spiel, um unser Spiel zu erstellen. Und hier: Ich klappe das jetzt kurz zusammen, denn unser Endpunkt wurde aufgerufen. Hier sehen Sie, dass ein Aufruf an den großzügigen Endpunkt erfolgt. Wir klicken drauf. Wir sehen den Weg, in die großzügige API zu gelangen, die wir gerade erstellt haben. Da ist es. Lasst uns gemeinsam ein ganz neues Spiel entwickeln. Wir sagen einfach, dass dies unser Astro-Vote-Spiel sein wird. Es handelt sich um ein Plattformspiel, also um ein Spiel mit Jump'n'Run-Elementen, das Geschicklichkeit und ein präzises Timing erfordert. Hier ist der Preis, und für den Tag legen wir fest, dass 9 6 20 24 gelten. Ähm, schließt es dann bitte ab. Klickt anschließend auf Speichern, damit eure Änderungen gespeichert werden. Und hier siehst du: Unser Aufruf zu Games liefert eine 201. Dies ist der Aufruf, das Spiel zu erstellen. Wir klicken darauf. Wir sehen, dass es sich um eine POST-Anfrage war und wir tatsächlich den Status 201 erhielten, ähnlich wie im REST-Client von VS Code. Wir könnten es auch aktualisieren; hier drei Fighter zwei. Das wird jetzt drei Fighter Zwei, nennen wir es mal 'Super'. Der Preis wird, sagen wir, vermutlich nur sieben Komma neun neun betragen, sehr billig. Klicken Sie auf Speichern. Und das Spiel ist aktualisiert, wie man hier sieht. Schließlich können wir fortfahren und Teste die Löschung eines Spiels. Sagen wir also, dass wir das Super Mario Bros. Wonder-Spiel nicht mehr möchten. Wir können hier auf den Lösch-Button klicken, dann auf Löschen, und das Spiel ist wirklich weg. Also, da hast du es. Äh, eine wirklich moderne Full-Stack-Anwendung, jetzt betrieben von der your.net-API. und Reaktionstext. Also, wohin gehen wir von hier genau? Zuerst die Code-Struktur, das ist die Grundlage unseres Codes. Derzeit ist alles an einem Ort – das wird in großen Anwendungen zum Albtraum. Man kann eine vertikal ausgerichtete Architektur verwenden, damit Funktionen sauber bleiben. Dann Authentifizierung und Autorisierung, speziell, wie Sie Ihre APIs mit Microsoft Intra ID absichern. Der branchenweite Standard, der heute in den meisten Großunternehmen gilt. Danach sollst du lernen, wie man deine API-Endpunkte testet, so wie echte Anfragen sie treffen, auch bekannt als Integrationstests. Dann möchtest du alles, was du gebaut hast, containerisieren und es in die Azure-Cloud verschicken. Hier wird dein Code jetzt wirklich zu einem echten Produkt. Und wenn du bereit bist, setze auf Full-Stack mit einem modernen React-Frontend, um eine echte, praxisnahe Anwendung von Anfang bis Ende zu erleben. Meistere diese Skills und entwickle produktionsbereite Backends, Schritt für Schritt in meinem .NET Backend-Bootcamp. Details findest du unter dotnetacademy.io/bootcamp. Danke fürs Zuschauen – wir sehen uns im nächsten Video.
Download Subtitles
These subtitles were extracted using the Free YouTube Subtitle Downloader by LunaNotes.
Download more subtitlesRelated Videos
Download Subtitles for Azure AI Foundry Basic Agent Setup
Enhance your learning experience by downloading accurate subtitles for the Azure AI Foundry Basic Agent Setup video. Follow step-by-step instructions easily with clear captions, ensuring you don't miss any crucial details. Perfect for accessibility and improved comprehension.
Download Java Full Course Subtitles for Free (2025)
Enhance your learning experience with downloadable subtitles for the Java Full Course 2025. Access accurate captions to follow along easily, improve comprehension, and review key concepts at your own pace.
Download Subtitles for Harvard CS50 2026 Computer Science Course
Enhance your learning experience with downloadable subtitles for the Harvard CS50 2026 full computer science course. Easily follow along with lectures, improve comprehension, and access the content offline anytime. Perfect for students and enthusiasts aiming to master computer science concepts.
C Language Tutorial Subtitles for Beginners with Practice
डाउनलोड करें C Language Tutorial के लिए सबटाइटल्स और कैप्शन्स, जिससे यह वीडियो और भी समझने में आसान हो जाता है। नोट्स और प्रैक्टिस प्रश्नों के साथ यह सीखने का आपका अनुभव बेहतर बनाएं।
Download Subtitles for Learn This Skill to Thrive in 10 Years
Enhance your understanding by downloading subtitles for the video 'Learn This Skill If You Want To Thrive In The Next 10 Years.' Subtitles help you grasp key concepts clearly and make learning accessible anytime, anywhere.
Most Viewed
Download Subtitles for 2025 Arknights Ambience Synesthesia Video
Enhance your viewing experience of the 2025 Arknights Ambience Synesthesia — Echoes of the Legends by downloading accurate subtitles. Perfect for understanding the intricate soundscapes and lore, these captions ensure you never miss a detail.
تحميل ترجمات فيديو الترانزستورات كيف تعمل؟
قم بتنزيل ترجمات دقيقة لفيديو الترانزستورات لتسهيل فهم كيفية عملها. تعزز الترجمات تجربة التعلم الخاصة بك وتجعل المحتوى متاحًا لجميع المشاهدين.
Download Subtitles for Girl Teases Friend Funny Video
Enhance your viewing experience by downloading subtitles for the hilarious video 'Girl Teases Friend For Having Poor BF'. Captions help you catch every witty remark and enjoy the humor even in noisy environments or for non-native speakers.
Download Accurate Subtitles and Captions for Your Videos
Easily download high-quality subtitles to enhance your video viewing experience. Subtitles improve comprehension, accessibility, and engagement for diverse audiences. Get captions quickly for better understanding and enjoyment of any video content.
離婚しましたの動画字幕|無料で日本語字幕ダウンロード
「離婚しました」の動画字幕を無料でダウンロードできます。視聴者が内容をより深く理解し、聴覚に障害がある方や外国人にも便利な字幕付き動画を楽しめます。

