Northwind Blazor Prototype Web App

Längere Zeit habe ich mich sozusagen geweigert über das neue UI Framework  Blazor zu bloggen. Dabei schreibt Telerik über den aspnet core Ableger, vom Nachfolger von ASP.NET Webforms. Nun in der Tat verspricht auf den ersten Blick, eine .NET (leider ohne VB.NET) Welt im Browser ganz ohne JavaScript aufzuerstehen. Aber das war es dann auch schon mit der Ähnlichkeit.

image

Mein Problem mit Blazor ist bisher eher, der unreife Zustand, der sich bis in die Namensgebung zieht. Der Preview hat aktuell die Version 8 erreicht, der Zyklus liegt bei nur 6 Wochen. Für den Microsoft Blogger ergibt sich das Problem, das nach einem Monat der Inhalt veraltet ist. So sind die Namen für die Server gerenderte Version nun Blazor Server App (früher mal teilweise was mit Razor Server vs Client) und die Browser gehostete Version führt nun Webassembly im Namen. Das macht alles Sinn, aber es ändert sich eben dauernd.

image

Mein etwas umfangreicheres Konferenz Beispiel hat mehrere Stunden gebraucht um alle Änderungen durchzuführen und weigert sich noch immer hartnäckig zu kompilieren. Nichts desto trotz soll in 2-3 Entwickler Zyklen (Oktober/November) zumindest für die Server Variante eine finale Version erscheinen. Also kein totes Pferd, sondern ein junger widerspenstiger Hengst den wir nun zureiten.

Mein Rodeo Circuit befindet sich außerhalb der Hello World Blazor Demos und ist trotzdem überraschend einfach. Die Northwind Customers Tabelle wird per Forward Paging im Browser dargestellt.

.NET Standard

Das Entity Framework  gibt es es als rewrite in dotnet core. Zum Zeitpunkt des hier geschriebenen in einer 8er preview Version. Nun ist Blazor 8 und ef 8 leider nicht kompatibel, weil ersteres .NET Standard 2.0 und zweiteres schon bei 2.1 ist. Irr oder? Kleinster gemeinsamer Nenner (das unterm Strich) ist 2.0 und dazu muss man die Preview 6 von EF core per Nuget installieren und das klappt dann auch wirklich.

image

Konkret installiere ich nur Microsoft.EntityFrameworkCore.SqlServer für einen Zugriff auf den Microsoft SQL Server.  Für die Generierung des Models lassen sich Scaffolding Kommando Zeilen Tools einsetzen oder man kopiert Model und Context Klassen aus einem anderen Projekt.

dotnet ef dbcontext scaffold "Server=.\;Database=northwind;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -o Model

Die Context Klasse erbt von DbContext enthält die üblichen DbSet verweise. Allerdings muss man noch die Connection irgendwo verwalten und das mache ich jetzt ganz unschön und unsicher im Code der C# Klasse.

   1:  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
   2:   {
   3:    if (!optionsBuilder.IsConfigured)
   4:      {
   5:      optionsBuilder.UseSqlServer("Server=(local);Database=northwind;Trusted_Connection=True;");
   6:      }
   7:  }

Die Model Klassen z.B. Customers.cs sehen aus wie immer in Entity Framework, egal ob klassisch .net oder core.

Blazor Basics

Als nächstes wird eine Razor View angelegt, die technisch immer als Komponente ausgeführt wird. Neu ist, das diese mit einem Großbuchstaben beginnen muss (der Tod von VB.NET). Im Beispiel Kunden.razor genannt.

image

Diese Minimal Version von nix muss nun ausgebaut werden. In der ersten Zeile die Page Direktive mit der Route unter der diese Seite später vom Benutzer zu finden sein soll. Optional auch mit Parameter in {} hinten dran, wie auch in ASP.NET core Razor cshtml Dateien.

In den @Code Block (vorher @function) wird in der Page die C# Logig implementiert um die Kunden Tabelle abzufragen und einer generischen Liste zuzuweisen.

   1:  @code
   2:  {
   3:      public List<Customers> listekunden;
   4:      northwindContext ef = new northwindContext();
   5:      protected override async Task OnInitializedAsync()
   6:      {
   7:          listekunden = ef.Customers.ToList();
   8:      }

Wirklich, das ist alles! So einfach! OnInitialized ist sozusagen das PageLoad.

Die Deklaration des Views geschieht auch mit einer Razor Syntax. Das Using muss auf den Namespace des Models verweisen. Ich weis das wisst ihr natürlich.

   1:  @page "/kunden"
   2:  @using Konftemp.Model;
   3:  <h1>Kunden Northwind</h1>
   4:  <ul>
   5:      @foreach (var item in listekunden)
   6:      {
   7:          <li>@item.CompanyName</li>
   8:      }
   9:  </ul>

Das ist der Punkt an dem sich die meisten mit einem #Awesome zurücklehnen. Aber es gibt mehr. Der Gag der ganzen Kiste ist, das Blazor den Status auf der Server Seite halten kann wie Java Script SPA Framwork das auf der Client Seite tut. Wir nutzen das um ein forward Paging zu implementieren. Zunächst wird die  Seitengröße im LINQ Query auf 10 Records festgelegt und ein Counter eingeführt.

   1:  @code
   2:  {
   3:      public int seitenr = 0;
   4:      public List<Customers> listekunden;
   5:      northwindContext ef = new northwindContext();
   6:      protected override async Task OnInitializedAsync()
   7:      {
   8:          listekunden = ef.Customers.Take(10).ToList();
   9:      }

 

Dieser Counter wird erhöht wenn der Benutzer auf den “mehr Datensätze” Button klickt. Die Notatíon bzw Position des @ hat sich in der letzten Blazor Preview 8 wieder geändert!

   1:  <button id="bottom" class="btn btn-primary"
   2:          @onclick="LoadNext">
   3:     More...
   4:  </button>

Und dann laden wir mal weiter unsere Datenhäppchen und hängen sie an das Listenobjekt an. Weniger Code geht nicht!

   1:  void LoadNext()
   2:  {
   3:     seitenr++;
   4:     listekunden.AddRange(ef.Customers.Skip(seitenr * 10).Take(10).ToList<Customers>());
   5:  }

JavaScript

Doch auch hier geht mehr. Irgendwann ist die Seite im Browser optisch gefüllt und die neuen Datensätze werden im nicht sichtbaren Bereich angelegt. Dann muss der Benutzer scrollen oder der Programmierer. Nur hier geht es nun mal nicht ohne JavaScript. Und Obacht: aktuell sehe ich keine Blazor Web App ohne JavaScript. Für die Interaktion mit dem DOM (also den darstellenden HTML Elementen) braucht man sehr häufig JS Code. Und so gibt es eine JSruntime Bridge die Zugriff von C# auf JS oder aus JS auf C# ermöglicht.

Da die Redmonder Jungs und Mädels von der modische DI Pattern (Dependency Injection) Geschichte total begeistert sind, instanzierung nicht über new, sondern a) über @inject im Page Kopf Bereich oder b) Attribut.

   1:  @code
   2:  {
   3:      [Inject]
   4:      IJSRuntime JSRuntime { get; set; }

Man gewöhnt sich an das DI Zeugs, aber schmecken tuts mir nur bedingt. Nun kann man eine JavaScript Funktion mit n-Parametern aufrufen und die Rückgabe auswerten. Dieses JavaScript muss man allerdings in eine statische Datei legen. Am besten _host.cshtml. Bis Version Preview 7 ging das nur so (jedenfalls bei mir). Mit aktueller Version kann man eine JavaScript API Funktion tatsächlich auch direkt aufrufen. Allerdings erst nachdem das Rendering fertig ist. Sonst Scrollt man nichts. Die JavaScript Funktion ist window.scrollTo die es auch in einer scroll Variante gibt. Die Koordinaten x und y.

   1:   protected override void OnAfterRender()
   2:      {  JSRuntime.InvokeAsync<bool>("scroll", 0, 1000);
   3:      }

Das habe ich durch probieren herausgefunden, also keine Garantie das in Preview 9 noch funktional.

forwardpaging

Kommentare sind geschlossen