Einführung
Ein kurzer Kurs zum Erstellen einer einfachen Webanwendung mit ASP.NET Core-Technologien, Entity Framework, Microsoft SQL Server DBMS und Angular Framework. Wir werden die Web-API über die Postman- Anwendung testen .
Der Kurs besteht aus mehreren Teilen:
- Erstellen Sie Web-APIs mit der ASP.NET-Web-API und dem Entity Framework Core.
- Implementierung der Benutzeroberfläche in Angular.
- Hinzufügen der Authentifizierung zur Anwendung.
- Erweitern Sie das Anwendungsmodell und erkunden Sie zusätzliche Funktionen des Entity Framework.
Teil 1. Erstellen Sie Web-APIs mit ASP.NET Web API und Entity Framework Core
Als Beispiel betrachten wir die jetzt klassische Anwendung einer To-Do-Liste. Zum Entwickeln der Anwendung verwende ich Visual Studio 2019 (der Vorgang ist in Visual Studio 2017 ähnlich).
Projekterstellung
Erstellen Sie ein neues ASP.NET Core-Webanwendungsprojekt in Visual Studio:
Benennen Sie die Anwendung und geben Sie den Pfad zum Verzeichnis mit dem Projekt an:
Wählen Sie die API-Anwendungsvorlage aus:
Modell
Erstellen wir einen Modellkatalog und fügen dem neuen Katalog die erste TodoItem.cs-Klasse hinzu, deren Objekte einige Aufgaben der Aufgabenliste in der Anwendung beschreiben:
public class TodoItem
{
public int Id { get; set; }
public string TaskDescription { get; set; }
public bool IsComplete { get; set; }
}
Wir werden SQL Server als DBMS verwenden und auf die Datenbank wird über Entity Framework Core zugegriffen. Zuerst werden wir das Framework über den integrierten NuGet-Paketmanager installieren:
Einer der Ansätze für die Arbeit mit dem Entity Framework ist der "Code-First" -Ansatz. Das Wesentliche des Ansatzes ist, dass basierend auf dem Anwendungsmodell (in unserem Fall repräsentiert das Modell eine einzelne Klasse - TodoItem.cs) die Struktur der Datenbank (Tabellen, Primärschlüssel, Links) gebildet wird, all diese Arbeiten „hinter den Kulissen“ und direkt mit Wir arbeiten nicht mit SQL. Voraussetzung für die Modellklasse ist das Vorhandensein eines Primärschlüsselfelds. Standardmäßig sucht Entity Framework nach einem Ganzzahlfeld, in dessen Namen sich eine Teilzeichenfolge "id" befindet, und bildet darauf basierend einen Primärschlüssel. Sie können dieses Verhalten mithilfe benutzerdefinierter Attribute oder mithilfe der Funktionen der Fluent-API überschreiben.
Die Hauptkomponente bei der Arbeit mit Entity Framework ist die Datenbankkontextklasse, über die tatsächlich auf die Daten in den Tabellen zugegriffen wird:
public class EFTodoDBContext : DbContext
{
public EFTodoDBContext(DbContextOptions<EFTodoDBContext> options) : base(options)
{ }
public DbSet<TodoItem> TodoItems{ get; set; }
}
Die Basisklasse DbContext erstellt den Datenbankkontext und bietet Zugriff auf die Funktionen des Entity Framework.
Wir werden SQL Server 2017 Express zum Speichern von Anwendungsdaten verwenden . Verbindungszeichenfolgen werden in einer JSON-Datei namens appsettings.json gespeichert:
{
"ConnectionStrings": {
"DefaultConnection": "Server=.\\SQLEXPRESS;Database=Todo;Trusted_Connection=true"
}
}
Als Nächstes müssen Sie die Startup.cs-Klasse ändern, indem Sie der ConfigureServices () -Methode den folgenden Code hinzufügen:
services.AddDbContext<EFTodoDBContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
Die AddDbContext () -Methode konfiguriert die vom Entity Framework Core bereitgestellten Dienste für die EFTodoDBContext-Datenbankkontextklasse. Das Argument für die AddDbContext () -Methode ist ein Lambda-Ausdruck, der ein Optionsobjekt empfängt, das die Datenbank für die Kontextklasse konfiguriert. In diesem Fall wird die Datenbank mithilfe der UseSqlServer () -Methode und unter Angabe einer Verbindungszeichenfolge konfiguriert.
Definieren wir die grundlegenden Vorgänge für die Arbeit mit Aufgaben in der ITodoRepository-Oberfläche:
public interface ITodoRepository
{
IEnumerable<TodoItem> Get();
TodoItem Get(int id);
void Create(TodoItem item);
void Update(TodoItem item);
TodoItem Delete(int id);
}
Diese Schnittstelle ermöglicht es uns, nicht über die spezifische Implementierung des Data Warehouse nachzudenken. Vielleicht haben wir uns nicht genau für die Wahl eines DBMS- oder ORM-Frameworks entschieden. Jetzt spielt es keine Rolle, welche Klasse, die den Datenzugriff beschreibt, von dieser Schnittstelle erbt.
Implementieren wir ein Repository, das, wie bereits erwähnt, von ITodoRepository erbt und EFTodoDBContext als Datenquelle verwendet:
public class EFTodoRepository : ITodoRepository
{
private EFTodoDBContext Context;
public IEnumerable<TodoItem> Get()
{
return Context.TodoItems;
}
public TodoItem Get(int Id)
{
return Context.TodoItems.Find(Id);
}
public EFTodoRepository(EFTodoDBContext context)
{
Context = context;
}
public void Create(TodoItem item)
{
Context.TodoItems.Add(item);
Context.SaveChanges();
}
public void Update(TodoItem updatedTodoItem)
{
TodoItem currentItem = Get(updatedTodoItem.Id);
currentItem.IsComplete = updatedTodoItem.IsComplete;
currentItem.TaskDescription = updatedTodoItem.TaskDescription;
Context.TodoItems.Update(currentItem);
Context.SaveChanges();
}
public TodoItem Delete(int Id)
{
TodoItem todoItem = Get(Id);
if (todoItem != null)
{
Context.TodoItems.Remove(todoItem);
Context.SaveChanges();
}
return todoItem;
}
}
Regler
Der Controller, dessen Implementierung im Folgenden beschrieben wird, weiß nichts über den Datenkontext von EFTodoDBContext, sondern verwendet bei seiner Arbeit nur die ITodoRepository-Schnittstelle, mit der die Datenquelle geändert werden kann, ohne den Controller zu ändern. Dieser Ansatz wurde von Adam Freeman in seinem Buch "Entity Framework Core 2 für ASP.NET Core MVC für Profis" als "Speicher" -Muster bezeichnet.
Der Controller implementiert Handler für Standard-HTTP-Anforderungsmethoden: GET, POST, PUT, DELETE, die den Status unserer in der Klasse TodoItem.cs beschriebenen Aufgaben ändern.
Fügen Sie die Klasse TodoController.cs mit dem folgenden Inhalt zum Verzeichnis "Controller" hinzu:
[Route("api/[controller]")]
public class TodoController : Controller
{
ITodoRepository TodoRepository;
public TodoController(ITodoRepository todoRepository)
{
TodoRepository = todoRepository;
}
[HttpGet(Name = "GetAllItems")]
public IEnumerable<TodoItem> Get()
{
return TodoRepository.Get();
}
[HttpGet("{id}", Name = "GetTodoItem")]
public IActionResult Get(int Id)
{
TodoItem todoItem = TodoRepository.Get(Id);
if (todoItem == null)
{
return NotFound();
}
return new ObjectResult(todoItem);
}
[HttpPost]
public IActionResult Create([FromBody] TodoItem todoItem)
{
if (todoItem == null)
{
return BadRequest();
}
TodoRepository.Create(todoItem);
return CreatedAtRoute("GetTodoItem", new { id = todoItem.Id }, todoItem);
}
[HttpPut("{id}")]
public IActionResult Update(int Id, [FromBody] TodoItem updatedTodoItem)
{
if (updatedTodoItem == null || updatedTodoItem.Id != Id)
{
return BadRequest();
}
var todoItem = TodoRepository.Get(Id);
if (todoItem == null)
{
return NotFound();
}
TodoRepository.Update(updatedTodoItem);
return RedirectToRoute("GetAllItems");
}
[HttpDelete("{id}")]
public IActionResult Delete(int Id)
{
var deletedTodoItem = TodoRepository.Delete(Id);
if (deletedTodoItem == null)
{
return BadRequest();
}
return new ObjectResult(deletedTodoItem);
}
}
Vor der Klassendefinition wird ein Attribut angegeben, das die Routenvorlage für den Zugriff auf den Controller beschreibt: [Route ("api / [controller]")]. Auf den TodoController kann über die folgende Route zugegriffen werden: https: // <Host-IP>: <Port> / api / todo. [Controller] gibt den Namen der Controller-Klasse in Kleinbuchstaben an, wobei der Teil "Controller" weggelassen wird.
Bevor jede Methode im TodoController definiert wird, wird ein spezielles Attribut des Formulars angegeben: [<HTTP-Methode> ("Parameter", Name = "Methodenalias")]. Das Attribut bestimmt, welche HTTP-Anforderung von dieser Methode verarbeitet wird, den Parameter, der im Anforderungs-URI übergeben wird, und den Alias der Methode, mit der die Anforderung erneut gesendet werden kann. Wenn Sie das Attribut nicht angeben, versucht das MVC-Framework standardmäßig, die am besten geeignete Methode im Controller zu finden, um die Anforderung basierend auf dem Namen der Methode und den angegebenen Parametern in der Anforderung zu verarbeiten. Wenn Sie also im TodoController-Controller kein Attribut für die Get () -Methode angeben, dann in einer HTTP-Anforderung Mit der GET-Methode: https: // <Host-IP>: <Port> / api / todo definiert die Infrastruktur die Get () -Methode des Controllers, um die Anforderung zu verarbeiten.
In seinem Konstruktor erhält der Controller einen Verweis auf ein Objekt vom Typ ITodoRepository, aber bisher weiß die MVC-Infrastruktur nicht, welches Objekt beim Erstellen des Controllers ersetzt werden soll. Wir müssen einen Dienst erstellen, der diese Abhängigkeit eindeutig auflöst. Dazu nehmen wir einige Änderungen an der Startup.cs-Klasse vor, indem wir der ConfigureServices () -Methode den folgenden Code hinzufügen:
services.AddTransient<ITodoRepository, EFTodoRepository>();
Die AddTransient <ITodoRepository, EFTodoRepository> () -Methode definiert einen Dienst, der eine neue Instanz der EFTodoRepository-Klasse erstellt, wenn eine Instanz des ITodoRepository-Typs erforderlich ist, beispielsweise in einem Controller.
Der vollständige Code für die Startup.cs-Klasse:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddDbContext<EFTodoDBContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
services.AddTransient<ITodoRepository, EFTodoRepository>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Migrationen
Damit das Entity Framework die Datenbank und die Tabellen aus dem Modell generieren kann, müssen Sie den Datenbankmigrationsprozess verwenden. Migrationen sind eine Gruppe von Befehlen, die die Datenbank auf die Arbeit mit dem Entity Framework vorbereiten. Sie werden zum Erstellen und Synchronisieren der Datenbank verwendet. Befehle können sowohl in der Package Manager-Konsole als auch in der Power Shell (Developer Power Shell) ausgeführt werden. Wir werden die Package Manager-Konsole verwenden. Um mit dem Entity Framework zu arbeiten, müssen wir das Microsoft.EntityFrameworkCore.Tools-Paket installieren:
Starten Sie die Package Manager-Konsole und führen Sie den Befehl Add-Migration Initial aus :
Im Projekt wird ein neues Verzeichnis angezeigt - Migrationen, in denen Migrationsklassen gespeichert werden, auf deren Grundlage Objekte in der Datenbank erstellt werden, nachdem der Befehl Update-Database ausgeführt wurde: Die
Web-API ist bereit. Durch Ausführen der Anwendung auf lokalem IIS Express können wir den Betrieb des Controllers testen.
Testen von WebAPI
Erstellen wir in Postman eine neue Sammlung von Anforderungen mit dem Namen TodoWebAPI:
Da unsere Datenbank leer ist , testen wir zunächst die Erstellung einer neuen Aufgabe. In der Steuerung ist die Create () -Methode für das Erstellen von Aufgaben verantwortlich, die eine von der POST-Methode gesendete HTTP-Anforderung verarbeiten und im Anforderungshauptteil ein serialisiertes TodoItem-Objekt im JSON-Format enthalten. Das Attribut [FromBody] vor dem Parameter todoItem in der Methode Create () weist das MVC-Framework an, das TodoItem-Objekt aus dem Anforderungshauptteil zu deserialisieren und als Parameter an die Methode zu übergeben. Erstellen wir eine Anfrage in Postman, die eine Anfrage an die webAPI sendet, um eine neue Aufgabe zu erstellen:
Die Create () -Methode leitet die Anforderung nach erfolgreicher Erstellung der Aufgabe mit dem Alias "GetTodoItem" an die Get () -Methode weiter und übergibt die ID der neu erstellten Aufgabe als Parameter. Als Ergebnis erhalten wir das erstellte Aufgabenobjekt im JSON-Format als Antwort auf die Anforderung.
Indem Sie eine HTTP-Anforderung mit der PUT-Methode senden und ein bereits erstelltes Objekt in der URI-ID (https: // localhost: 44370 / api / todo / 1) angeben und im Anforderungshauptteil ein Objekt mit einigen Änderungen im JSON-Format übergeben, ändern wir dieses Objekt in der Datenbank :
Bei einer HTTP-Anforderung mit der GET-Methode ohne Angabe von Parametern erhalten wir alle Objekte in der Datenbank:
Eine HTTP-Anforderung mit der DELETE-Methode und die Angabe der ID des Objekts in der URI (https: // localhost: 44370 / api / todo / 2) löschen das Objekt aus der Datenbank und geben JSON mit zurück Remote-Aufgabe:
Das ist alles, im nächsten Teil werden wir die Benutzeroberfläche mit dem Angular JavaScript Framework implementieren.