ASP.NET Core UI Controls per ViewComponent

Manche Dinge habend die Microsoft Entwickler ganz einfach gemacht, wie ein Razor Partial und manchen Dinge sind furchtbar kompliziert und mit magic versehen, wie die Middleware von ASP.NET core. Die sogenannten View Components sind von beiden etwas, einfach und kompliziert. Um das zu verdeutlichen wird anhand eines Endless Paging Anwendungsfall durch die Northwind Customer Tabelle geblättert.

viewcomp

Es wird benötigt ein SQL Server Instanz mit der Northwind Datenbank und passenden Zugriffsrechten. Im Visual Studio Projekt müssen folgende Assemblies am besten per Nuget Paketmanager Kommandozeile oder Assistenten installiert sein.

Install-Package Microsoft.EntityFrameworkCore.Tools
Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design

Aus der Paket Manager Console wird dann das Model und die Enity Klassen erzeugt.  Folgendes Gerüstbau Kommando bitte anpassen bezüglich Server Credentials und Ausgabeverzeichnis im Visual Studio ASP.NET Core Projekt.

Scaffold-DbContext "localhost;Database=Northwind;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models

Um die Datenbank auch zur Laufzeit nutzen zu können wird der Connection String in der Datei Appsettings.json eingetragen. Visual Studio bietet dazu einen in JSON eigentlich nicht vorgesehenen Schema support per Intellisense.

   1:  {
   2:    "ConnectionStrings": {
   3:      "Northwind": "Data Source=localhost;Initial Catalog=Northwind;Integrated Security=True"

Richtig aufwändig wird es die Datenbank Connection bzw das Context Model per DI zur Verfügung zu stellen. Dazu wie immer startup.cs und die ConfigureServices Methode um foglenden C# Code erweitern

   1:  services.AddDbContext<northwindContext>(options =>
   2:         options.UseSqlServer(Configuration.GetConnectionString("Northwind")));

 

Als nächstes wird die ViewComponent Klasse erzeugt, die die Logik beinhalten wird für das forward paging in den Customer Daten. Der Speicherort spielt keine Rolle. Der Name aber schon. So soll das Suffix ViewComponent angehängt werden, oder die Klasse ViewComponent geerbt werden oder ein Klassenattribut ViewComponent. Im folgenden C# Code kommt alles drei zum Einsatz. Ich bin der Meinung Inheritance ist besser als die Konvention per Suffix. Der Zusatz wird jedenfalls automatisch in der späteren Nutzung der ViewComponent als UI Element PagedCustomers  entfernt.

Der DB Context wird nun per Constuctor Injection referenziert. Die Datenbank SQL Abfrage dann in Zeile 12 per ToList durchgeführt anhand der vorher definierten LINQ Paging Logik.  Wieder in der Kategorie Magic ist die Zuweisung der generischen Liste als Model in eine View.

   1:  [ViewComponent(Name = "PagedCustomers")]
   2:  public class PagedCustomersViewComponent : ViewComponent
   3:  {
   4:     private northwindContext _db;
   5:     public PagedCustomersViewComponent(northwindContext db)
   6:     {
   7:              _db = db;
   8:     }
   9:     public IViewComponentResult Invoke(int page = 0)
  10:     {
  11:        IQueryable<Customers> query = _db.Customers.Skip(page*10).Take(10);
  12:        List<Customers> model = query.ToList();
  13:        return View(model);
  14:     }
  15:  }

Wo ist sie denn die View? Wie immer in aspnetcore gibt es mehrere Möglichkeiten. Man kann den View benennen. Tut man das nicht wie hier, gilt ein default.cshtml. Dieser muss sich in einem bestimmten Verzeichnis befinden, das so wie die ViewComponent PagedCustomer heißen muss und in einem Unterordner Components liegen muss. Das wiederrum kann in shared Views oder Pages usw. . Kurz gesagt machen Sie es genauso wie im Bild und alles wird gut

image

Die ViewComponent ähnelt einem Razo Partial. Im Unterschied zu diesem, aber mit eigenen unabhängigen Page Model. Hier wird das HTML Layout einer Table Row mit den Tabellen Feldern verknüpft wie man das z.B. aus einem MVVM Ansatz kennt. Der Code in Zeile 1 Using sieht in Ihrem Projekt anders aus. Je nachdem wie der Projektname lautet und wo Ihr Entity Framework core Model ruht.

   1:  @using DUSCoreTraining.Models
   2:  @model List<Customers>
   3:  @foreach (var item in Model)
   4:  {
   5:    <tr>
   6:    <td>@item.CustomerId</td>
   7:    <td>@item.CompanyName</td>
   8:    <td>@item.ContactName</td>
   9:    </tr>
  10:  }

Das war schon. In Stufe 1 wird die ViewComponent in einer neuen Razor Page verwendet. Legen Sie eine Page an (zb ViewComp.cshtml)

Dazu gibt es mind. 2 Möglichkeiten. Die einfachere per Component.Invoke, im Beispiel auskommentiert. Oder die schönere per Taghelper. Das Prefix vc: ist Konvention. Eine weitere Konvention ist das sogenannte Kebab-Casing der Namen und Eigenschaften. So wird aus PagedCustomers –>paged-customers. Addtaghelper verweist auf den DLL Namen des Projektes.

   1:  @addTagHelper *, DUSCoreTraining
   2:  <h1>viewcomp</h1>
   3:  <table id="table1">
   4:      <vc:paged-customers page="@Model.seite"></vc:paged-customers>
   5:      @*@await Component.InvokeAsync("PagedCustomers", new { page = 0 })*@
   6:  </table>

Um die Page testen zu können, benötigt das PageModel (codebhind cshtml.cs) noch ein Property seite vom Typ Int.

Das Beispiel wird aber noch um die Ajax Server Paging Funktion erweitert, wie man es in einer SPA Anwendung mit Angular oder VUE.js so machen würde. Nur praktisch ohne JavaScript Bibliothek.

Ergänzen Sie das Pagemodel um eine OnPost Methode, die die ViewComponent mit dem Pagingoffset Parameter füllt. Damit wird bei jedem Aufruf der Page Counter Seite um eins erhöht und 10 weitere Datensatz als HTML TR Reihe an den Browser gesendet.

   1:  [IgnoreAntiforgeryToken(Order = 1001)] //sonst 400 ValidateAntiForgeryToken attribute default  order 1000,
   2:  public class viewcompModel : PageModel
   3:  {
   4:    public int seite { get; set; }
   5:    public ViewComponentResult OnPost()
   6:    {
   7:        seite++;
   8:        return ViewComponent("PagedCustomers", new {page = seite});
   9:   }

Das Attribut AnitForgeryToken wird zwingend benötgt, andernfalls es zu einer HTTP 400 Fehlermeldung kommt.

Der folgende JavaScript Code nutzt noch ein wenig JQuery. Die Funktion lade wird z.B. durch einen Hyperlink per OnClick aktiviert. Dadurch wird ein XMLHttpRequest im Hintergrund ausgeführt, so das der Benutzer nichts merkt. Wenn der Callback durch ist, findet sich die Code Ausführung in done wieder. Die dabei zurück gegebene Zeichenkette (daten) wird an das HTML Element per Append angefügt.

   1:    function lade() {
   2:          $.ajax({
   3:              url: 'viewcomp',
   4:              type: 'POST'
   5:          }).done(function (daten) {
   6:              $('#table1').append(daten);
   7:              let target = document.querySelector("#nachladen");
   8:              target.scrollIntoView({
   9:                  behavior: 'smooth',
  10:                  block: 'start'
  11:              })
  12:              e.preventDefault();
  13:              });
  14:          }
  15:    

 

Damit der Benutzer wieder am Ende der Tabelle steht wird noch ganz smooth ans Ende gescrollt. Das Ende der Tabelle definiert sich mit dem HTML Element (zb Button oder Hyperlink) mit der ID nachladen.

Kommentare sind geschlossen