Neues in ASP.NET 5, Teil 2: View Components

Werkzeuge  –  0 Kommentare

View Components sind neue Instrumente zum Erstellen wiederverwendbarer Webseitenbausteine in ASP.NET MVC 6.0. Sie bieten eine Kompetenztrennung entsprechend dem MVC-Prinzip (Model View Controller).

ASP.NET MVC bietet schon in den bestehenden Releases einige Instrumente der Wiederverwendbarkeit. Dazu gehören Razor Helper (@helper/@functions), HTML Helper Extension Methods, Partial Views und die ViewStart.cshtml-Datei. In ASP.NET MVC 6.0, das Kernbestandteil des plattformunabhängigen ASP.NET 5.0 ist, gibt es nun zwei weitere Möglichkeiten, Webseiten in wiederverwendbare Bausteine zu strukturieren: Tag Helper und View Components.

Neues in ASP.NET 5

Webseiten in ASP.NET MVC bestehen aus einer View (HTML- plus Programmcode in Razor-Syntax) und einem Controller (reiner Programmcode). Eine Partial View ist ein Teil einer View, die sich mit @Html.Partial() oder @HTML.RenderPartial() in mehrere Views einbinden lässt. Sie besitzt aber keinen eigenen Controller. Hier arbeitet im Hintergrund immer der Controller der View, in der die Partial View eingebunden wurde. An dieser Stelle setzt das neue Konzept der View Components in ASP.NET MVC 6.0 an. Sie bestehen im Gegensatz zur Partial View sowohl aus einer View als auch aus einem Controller.

Controller-Vielfalt

Der Controller einer View Component ist eine .NET-Klasse, die von der Klasse Microsoft.AspNet.Mvc.ViewComponent erbt. Sie muss öffentlich, darf nicht abstrakt und kann auch nicht in eine andere Klasse eingebettet sein, dafür aber an beliebiger Stelle im Projekt liegen. Der Name der Controller-Klasse für die View Component kann, muss aber nicht einer Konvention folgen. Wenn der Klassenname auf die Zeichenfolge "ViewComponent" endet, bilden die davor stehenden Buchstaben den Namen der View Component. Möchten Entwickler dieser Konvention nicht folgen, müssen sie die Klasse mit [ViewComponent(Name=xy)] annotieren. Der folgende Code zeigt die Controller-Klasse für die View Component "FlugTabelle", die mit dieser Annotation arbeitet, weil die Klasse selbst "FlugTabelleController" heißt.

using Microsoft.AspNet.Mvc;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace ASPNET5.Components
{
[ViewComponent(Name = "FlugTabelle")]
public class FlugTabelleController : ViewComponent
{
EF7_Kontext.WWWingsContext ctx = new EF7_Kontext.WWWingsContext();
public FlugTabelleController()
{
System.Diagnostics.Debug.WriteLine("FlugTabelleViewComponent
instanziiert: Kontextinstanz #" + ctx.ID);
}

public IViewComponentResult Invoke(string Ort, int Anzahl)
{
// Ort merken für die View
ViewBag.Ort = Ort;

// synchrone Datenbankabfrage
var liste = ctx.FlugSet
.Where(f => f.Datum > DateTime.Now.AddDays(2) && f.FreiePlaetze > 0)
.Where(f => f.Abflugort == Ort || f.Zielort == Ort)
.OrderBy(f => f.Datum)
.Take(Anzahl)
.ToList();

// fallweise eine der beiden Views aufrufen
if (liste.Count == 0) return View("KeineGefunden", liste);
return View(liste);
}

public async Task<IViewComponentResult> InvokeAsync(string Ort,
int Anzahl)
{
// Ort merken für die View
ViewBag.Ort = Ort;

// asynchrone Datenbankabfrage
var listeAsync = ctx.FlugSet
.Where(f => f.Datum > DateTime.Now.AddDays(2) && f.FreiePlaetze > 0)
.Where(f => f.Abflugort == Ort || f.Zielort == Ort)
.OrderBy(f => f.Datum)
.Take(Anzahl)
.ToListAsync();

// Daten asynchron abrufen
var liste = await listeAsync;

// fallweise eine der beiden Views aufrufen
if (liste.Count == 0) return View("KeineGefunden", liste);
return View(liste);
}
}
}

Die View-Component-Controller-Klasse muss die Methode Invoke() und/oder InvokeAsync() implementieren. Die Controller-Klasse (siehe zweites Beispiel) bietet beides, sowohl den synchronen Aufruf mit Invoke() als auch den asynchronen mit InvokeAsync() an. Beide Methoden in obigen Listing liefern die gleichen Daten unter Verwendung von Microsofts objektrelationalem Mapper Entity Framework: die nächsten Flüge, die mindestens zwei Tage in der Zukunft liegen und noch nicht ausgebucht sind. Für die Praxis ist die asynchrone Implementierung bei allen Aktionen vorzuziehen, die externe Ressourcen wie Datenbanken verwenden, da hierbei während der Datenbankabfrage der Webserver-Thread freigegeben wird und für andere Aufgaben zur Verfügung steht.

Beide Methoden haben zwei benutzerdefinierte Parameter: eine Zeichenkette für den Ort und eine Anzahl. Der Ort dient als Filter für die Flugstrecke – die Anzahl steuert, wie viele Flüge maximal aus der Datenbank geholt werden. Beide Methoden speichern auch den Ort im dynamischen View Bag und geben somit der View die Möglichkeit, diese Zusatzinformation zu verwerten. Denkbare Rückgabetypen von Invoke() und InvokeAsync() sind neben den Instanzen der Klasse View Component einfache Zeichenketten (Klasse String).