Tutorium: Verbindung von ASP.NET-Core- und Angular-4-App im Docker-Container mit der SQL-Azure-Datenbank
Im zweiten Teil unseres Tutoriums wollen wir Folgendes erreichen:
- eine MS-SQL-Datenbank im Azure-SQL-Server erstellen
- die erstellte Datenbank unter Verwendung von Entity Framework Core verbinden und Daten abrufen
- empfangene Daten mit Hilfe von Angular 4 anzeigen lassen
- die .NET-Core-Lösung in einen Docker-Container packen
- den Docker-Container bei Microsoft Azure einsetzen
Schauen wir uns jeden dieser Schritte genauer an.
Datenbank erstellen
Wir könnten einen lokalen SQL-Server verwenden, doch wir wollen unseren Proof of Concept attraktiver, portabler und relevanter in Bezug auf die modernen Herausforderungen machen. Deshalb werden wir unsere MS-SQL-Datenbank in die Azure-SQL-Datenbank verschieben.
Melden Sie sich zuerst im Microsoft-Azure-Portal an. Wenn Sie noch kein Abonnement haben, können Sie eine Testversion starten.
Klicken Sie auf das große Plus-Zeichen auf der linken Seite des Azure-Portals, wählen Sie „SQL Server“ aus und füllen Sie alle erforderlichen Felder wie unten dargestellt aus:
Erstellen Sie jetzt eine Datenbank, in der Sie die Daten speichern wollen, auf dem unteren Screenshot ist ein Beispiel dargestellt. Bitte beachten Sie, dass wir im Feld „Server“ den Servernamen ausgewählt haben, den wir zuvor erstellt haben, wie auf dem oberen Screenshot zu sehen ist.
Der nächste Schritt sind die Firewall-Einstellungen Ihrer Datenbank:
Endlich ist unsere Datenbank einsatzbereit, wobei sie immer noch leer ist.
Gehen wir nun zu unserer Anwendung mit .NET Core und Angular 4, die wir im ersten Teil unseres Tutoriums erstellt haben. In der früheren Version von ASP.NET wurde wahrscheinlich web.config genutzt, um die Verbindungszeichenkette zu speichern. Die Datei appsettings.json ist ein Analogon der Datei web.config im .NET Core. Die Zusammenstellung einer Verbindungszeichenkette für die Verbindung mit der Azure-Datenbank kann kompliziert erscheinen, aber Azure hilft uns dabei.
Öffnen Sie Ihre Azure-Datenbank und wählen Sie die Option „Schnellstart -> Datenbank-Verbindungszeichenkette für gängige Plattformen und APIs“:
Jetzt können Sie Ihre Datenbank-Verbindungszeichenkette sehen:
Öffnen Sie nun die Datei appsettings.json und präzisieren Sie dort die Verbindungszeichenkette:
Fügen Sie die folgenden Zeilen in die *.csproj-Projektdatei ein, um Entity Framework Core zu verwenden:
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.1" /> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
Jetzt führen Sie den Befehl dotnet restore aus, um diese Pakete herunterzuladen.
Dann können wir zum nächsten Schritt übergehen.
Erstellung des Datenbankmodells
Wir sollten POCO-Klassen für unser erstes Modell im Entity Framework Code vorbereiten. Lassen Sie uns ein Modell mit Hilfe von DataAnotation und FluentAPI wie unten dargestellt erstellen:
Wir überspringen hier mal den ganzen Code für diese Klassen, um den Rahmen nicht zu sprengen, laden Sie den Code einfach aus unserem Git-Repository herunter.
Erstellen Sie jetzt den Ordner DBModel und kopieren Sie die Dateien aus dem Repository in den Ordner, wie unten dargestellt:
Überprüfen Sie die HRContext-Datei, die die DbContext-Beschreibung enthält:
using Microsoft.EntityFrameworkCore; using System.Collections.Generic; namespace Ng2AspCore.DBModel { public class HRContext : DbContext { public HRContext(DbContextOptions<HRContext> options): base(options) { } public DbSet<Employee> Employees { get; set; } public DbSet<Project> Projects { get; set; } public DbSet<RoleAssignment> RoleAssignments { get; set; } } }
Wir sollten die Datei Startup.cs abändern, um die HRContext-Klasse als Service für den Dependency-Injection-Ansatz hinzuzufügen und die SQL-Server-Verbindung zu spezifizieren, die von HRContext verwendet wird:
using Ng2AspCore.DBModel; using Microsoft.EntityFrameworkCore; ….. services.AddDbContext<HRContext>(options => options.UseSqlServer(Configuration.GetConnectionString("AzureDbConnection")));
Der Code ist fertig. Führen Sie nun den folgenden Befehl aus, um die Migrationsdateien zu erstellen:
dotnet ef migrations add HRContextMigration -c HRContext -o DBModel/Migrations
Wie wir sehen können, wurde der Ordner „Migration“ erstellt.
Führen Sie den folgenden Befehl aus, um unsere Migrationsdateien in die Datenbank zu übernehmen:
dotnet ef database update –context HRContext
Wenn wir die Datenbank jetzt öffnen, werden wir nach der Ausführung dieses Befehls die neu erstellten Tabellen sehen, die den POCO-Klassen entsprechen.
Bitte beachten Sie, dass Sie die Entwicklung der Datenbank nicht unbedingt bei den Code-First-Klassen beginnen müssen. Als Alternative, wenn Sie bereits eine Datenbank haben, können Sie die reversible Entwicklung einer vorhandenen Datenbank vornehmen, wie Microsoft in seinem Beispiel zeigt.
Füllung der Datenbanktabellen
Wir haben Tabellen in unserer Testdatenbank erstellt und es ist höchste Zeit, sie mit Daten zu füllen.
Wir haben einige Demo-Daten vorbereitet, die Sie im Git-Repository finden:
Wie wir bereits erwähnt haben, ist Visual Studio Code eine leistungsfähige plattformübergreifende IDE, die mit Erweiterungen wunderbar angepasst werden kann. VS Code hat eine sehr schöne mssql-Erweiterung, die die Verbindung sowohl zur Microsoft-SQL-Server-Datenbank als auch zur Azure-SQL-Datenbank ermöglicht und SQL-Skripte ausführen kann:
Die Datei Employees.sql enthält die INSERT-Anweisungen. Um die Mitarbeitertabelle mit Demodaten zu füllen, drücken Sie Strg+Umschalt+P und geben Sie „mssql“ ein. Sie werden eine Reihe von Optionen angezeigt bekommen, z.B., „Verbinden“, „Anfrage ausführen“ und andere:
Wählen Sie die Option „MS SQL: Execute Query“, um den Inhalt der Datei Employees.sql zu übernehmen. Sie können die Antwort im rechten Teil des Fensters sehen. Führen Sie den Rest der Dateien auf die gleiche Weise aus:
Nun wollen wir uns mit unseren Backend beschäftigen.
Backend-Teil
Fügen Sie einen neuen Controller „EmployeeController.cs“ im Ordner „Controller“ hinzu:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Ng2AspCore.DBModel; namespace Ng2AspCore.Controllers { [Route("api/Employee")] public class EmployeeController : Controller { HRContext hrContext; public EmployeeController(HRContext hrContext) { this.hrContext = hrContext; } [HttpGet("GetAll")] public IActionResult GetAllEmployees() { var query = from emp in hrContext.Employees join rm in hrContext.RoleAssignments on emp.EmployeeId equals rm.EmployeeId where rm.Position == "Software developer" select emp; return Ok(query.ToList()); } } }
Bei der Methode GetAllEmployees führen wir eine LINQ-to-SQL-Abfrage durch, um alle an Projekten beteiligten Mitarbeiter als „Softwareentwickler“ zu kennzeichnen.
Frontend-Teil
Jetzt sind wir gut darauf vorbereitet, den Frontend-Teil unserer Anwendung mit Hilfe von Angular 4 zu erstellen, um empfangene Daten anzeigen zu lassen.
Laden Sie die Ordner “employees” und “models” mit dem Angular-4-Code aus dem Git-Repository herunter und fügen Sie sie im App-Ordner hinzu.
Lassen Sie uns nun Einiges überprüfen. Die Datei employee.service.ts ist ein typischer Dienst für Dependency Injection, der die Endpunkt-Antwort api/Employee/GetAll verarbeitet:
Der Code employee-list.component.ts enthält die Anmeldung zum Beobachtungskanal aus dem oben genannten Dienst:
In der Datei employee-list.component.html sehen Sie eine „ngFor“-Strukturlinie, die für die wiederholte Anzeige einer Reihe von bestimmten Mitarbeitern und die „Datum“-Auswahl erforderlich ist:
Schließlich müssen Sie einen „Selektor“ aus der Datei employee-list.component.ts in die Datei app.component.html einfügen:
Vergessen Sie nicht, die Komponente und den Dienst in app.module.ts anzumelden:
Unsere Anwendung ist fertig. Führen den webpack-Befehl aus, um die geänderten TypeScript-Dateien erneut zu sortieren, führen Sie ferner den Befehl dotnet run zur Wiederherstellung aus und lassen Sie die .NET-Core-Anwendung auf dem Kestrel-Server laufen. Sie sollen die gleiche Seite im Browser sehen, wie sie unten dargestellt ist. Beachten Sie, dass die Menschen in der Tabelle „Softwareentwickler“ sind:
Verschieben wir Ihre App nun in den Docker-Container, nachdem wir einige Grundlagen durchgegangen sind.
Docker-Grundlagen
Docker ist eine Software zur Automatisierung des Deployments und Managements von Anwendungen in der Virtualisierungsumgebung auf der Betriebssystemebene. Mit anderen Worten ist Docker eine „Sandbox“ für Ihre Anwendung. Die meisten Ressourcen beziehen sich auf Docker als „eine Plattform für Container“. Wenn Sie noch nie mit Docker gearbeitet haben, kann es schwierig sein, das Konzept eines Containers zu verstehen. Nehmen wir an, dass Sie mit dem VM-Konzept zumindest etwas vertraut sind.
Klären wir schnell die wichtigsten Unterschiede zwischen einer VM und einem Container:
Wie Sie anhand des obigen Beispiels sehen können, ist der Hauptunterschied zwischen einer VM und einem Container die Tatsache, dass der Container kein Gast-Betriebssystem als Schicht aufweist. Die VM entnimmt der Host-Maschine den Speicherplatz für den Eigenbedarf. Der Container teilt den Speicherplatz mit Ihrem Host-Betriebssystem. Schlussendlich ist der Container viel leichter als die VM. Wenn Sie jedoch ein völlig isoliertes Betriebssystem benötigen, sollten Sie eine VM verwenden.
Wenn Sie bereit sind, gehen wir zur Erstellung eines Docker-Containers über.
Erstellung der Dockerdatei und des Containers
Eine Dockerdatei ist ein Skript, das eine Reihe von Befehlen zur Installation eines Containers enthält. Die Docker-Plattform verwendet diese Datei, um ein „Docker image“ zu montieren, wenn Sie einen „Docker build“ ausführen. Um eine Dockerdatei zu erstellen, müssen Sie eine Textdatei genau mit dem Namen „Dockerfile“ erstellen und die Dateierweiterung entfernen.
Erstellen Sie eine Dockerdatei in der Wurzel Ihres Projekts und fügen Sie darin den folgenden Code ein:
FROM microsoft/aspnetcore:1.1 ARG source=. WORKDIR /app EXPOSE 80 COPY $source . ENTRYPOINT ["dotnet", "Ng2AspCore.dll"]
Schauen wir uns jede Anweisung einzeln an:
- FROMbestimmt das Bild microsoft/aspnetcore:1.1 zur Basis für nachfolgende Anweisungen. Es wird das Bild microsoft/aspnetcore:1.1 aus den Öffentlichen Repositorys übernommen, aber Sie können jedes andere Startbild aus einem beliebigen Archiv verwenden. Bitte beachten Sie, dass die Ziffern auf dem microsoft/aspnetcore:1.1 eine Markierung sind, die uns die in einem Container verwendete Version von .NET Core anzeigt. Sie könnten eine neuere Version von .NET Core nutzen, daher kann sich die Markierung unterscheiden.
- ARGsetzt eine Variable, dass die Benutzer zu dem Befehl „Docker build“ weitergehen dürfen. In der oben gezeigten Datei haben wir einen Standardwert angegeben.
- WORKDIR bestimmt das Arbeitsverzeichnis für die Anweisungen ENTRYPOINT und COPY, die wir in unserer Dockerdatei verwenden.
- EXPOSE informiert Docker, dass der Container beim Laufen auf die angegebenen Netzwerkanschlüsse reagiert. In unserem Fall hören wir auf Port 80.
- COPY kopiert Verzeichnisse oder Dateien und fügt sie im Dateisystem des Containers ein. Wir werden die Dateien aus dem Verzeichnis, auf dem die Dockerdatei gespeichert ist, in die Wurzel des Containers kopieren.
- ENTRYPOINT lässt einen Container als ausführbar laufen. In unserem Fall ist es das Gleiche wie dotnetdll in .NET Core CLI.
Nun ist unsere Dockerdatei in der Wurzel des Projektes gespeichert.
Doch laut ENTRYPOINT hat Docker Ng2AspCore.dll auszuführen. Wir können die Dockerdatei in den Zielordner rüberkopieren, der die erwartete .dll-Datei enthält ODER WORKDIR oder COPY ändern.
Im folgenden Beispiel haben wir den ersten Weg gewählt. Um die Dockerdatei nach jedem Build automatisch kopieren zu können, müssen wir das Verhalten der Dockerdatei innerhalb des Projekts ändern.
Öffnen Sie die *.csproj-Datei und ändern Sie die Informationen über Dockerfile:
<ItemGroup> <None Update="Dockerfile"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> </ItemGroup>
Momentan ist alles vorbereitet, um das Projekt und den Docker-Container zu erstellen. Gehen Sie zur Wurzel des Projekts und führen Sie folgende Befehle aus:
dotnet build dotnet publish
Nun können Sie das Verzeichnis öffnen, in dem die dll-Datei erstellt wurde:
<your project path>bin\Debug\netcoreapp1.1\publish
Die Dateien dll und Dockerfile sind in diesem Verzeichnis.
Jetzt können wir unseren eigenen projektspezifischen Container erstellen:
docker build bin\Debug\netcoreapp1.1\publish -t ng2aspcorecontainer
wo “bin\Debug\netcoreapp1.1\publish” der Pfad zu der Dockerdatei ist und “-t” der Name des Containers ist.
Führen Sie den folgenden Befehl aus:
docker run -it -d -p 8123:80 ng2aspcorecontainer
wobei “-it” eine interaktive tty (eine textuelle Input-Output-Umgebung) im Docker-Container platziert, “-p” an Port 80 (von EXPOSE definiert) des Containers und Port 8123 auf dem lokalen Host der Host-Maschine bindet und “-d” den Container im separaten Modus startet. Dies bedeutet, dass der Container vorhanden ist, während der Wurzelprozess vorhanden ist, der zum Laufen des Containers verwendet wird.
Schließlich haben wir unseren Docker-Container, der da ist und läuft. Sie können den Status durch den Befehl docker ps überprüfen.
Lassen Sie uns jetzt seinen Status überprüfen, indem Sie auf http://localhost:8123/ gehen, wobei Port 8123 derjenige ist, den wir zuvor definiert haben.
Docker-Repository
Jetzt müssen wir unser frisch erstelltes Bild in den Docker Hub (ein Satz von Repositorys) reintun. Gehen Sie auf https://www.docker.com/ und melden Sie sich an oder erstellen Sie Ihr Konto. Docker Hub ähnelt dem GitHub-Repository. Sie können Ihr Bild im Hub platzieren und es wiederverwenden, wo immer Sie wollen.
Führen Sie den folgenden Befehl aus, um sich in Ihrem Repository anzumelden:
docker login
Als Nächstes erstellen Sie das Tag <your repository name>/<image name>:<tag>, das auf ng2aspcorecontainer (das Quellbild) verweist.
docker tag ng2aspcorecontainer bastiuchenko/ng2aspcorecontainer:version1
Nun können Sie Ihr Dockerbild veröffentlichen:
docker push bastiuchenko/ng2aspcorecontainer:version1
Das Bild wurde in Ihrem Repository platziert, wie im Beispiel unten zu sehen ist:
Lassen Sie uns prüfen, ob Ihr Container aus dem Repository heraus ausgeführt werden kann. Führen Sie den folgenden Befehl aus:
docker run -p 8456:80 bastiuchenko/ng2aspcorecontainer:version1
Überprüfen Sie das Ergebnis in einem Browser:
Nur noch ein Schritt bleibt übrig und zwar, das Ganze auf Azure zu verschieben.
Containeraufbewahrung in Azure
Unsere Anwendung funktioniert lokal. Lassen wir sie auf Azure laufen, um überall darauf zugreifen zu können.
Gehen Sie zum Azure-Portal, klicken Sie auf das große Plus-Zeichen auf der linken Seite und wählen Sie die Option “Web App On Linux” aus:
Geben Sie den Namen Ihrer Web-App ein, klicken Sie auf“Configure container” und wählen Sie“Docker Hub” aus. Wir haben unser Bild in ein öffentliches (kostenloses) Repository verschoben, deshalb haben wir die Option „Public“ ausgewählt, wie Sie unten sehen können. Sie können auch ein privates Repository beim vorherigen Schritt auswählen.
Gehen Sie auf http://<app name>.azurewebsites.net und Sie werden das gleiche Ergebnis wie bei einem lokalen Test sehen:
Die finale Version dieses Proof of Concept finden Sie im GitHub-Repository. Zögern Sie wie immer nicht, Ihre Kommentare zu äußern oder uns zu kontaktieren, wenn Sie Fragen haben.
Im nächsten Teil unserer Tutorien werden wir eine ASP.NET-Core- und Angular-4-Anwendung mit der Verbindung zu MongoDB in Ubuntu erstellen und über das Zusammenspiel zwischen den Docker-Containern schreiben.