Onlangs heeft Growteq voor een bestaande klant een nieuwe applicatie ontwikkeld. Een van de requirements was dat deze applicatie ook gedeeltelijk offline gebruikt kan worden. Om dit te verwezenlijken, hebben we ervoor gekozen om gebruik te maken van het Blazor framework van Microsoft. Voor de user-interface hebben we in dit project gekozen voor DevExpress voor Blazor om snel mooie en uitgebreide pagina’s in elkaar te kunnen zetten.

We hebben gekozen voor de Blazor Server variant waarbij de applicatie niet volledig in de browser draait, maar via een API communiceert met code op de server. Deze communiceert met een SQL Server database en Azure B2C voor de authenticatie. Onze .NET solution bestaat uit drie projecten:

  • Client
  • Server
  • Shared

Client
Zoals de naam al doet vermoeden, bevat het clientproject alle code die op de client draait, in de browser van de gebruiker van de applicatie. Deze .razor bestanden zijn de basis voor de HTML-pagina’s, plus CSS-bestanden voor de styling, afbeeldingen zoals logo’s, libraries zoals Bootstrap, Font Awesome, en tenslotte Javascript. Er zijn .razor bestanden die een pagina renderen en .razor bestanden die een component renderen dat in meerdere pagina’s opgenomen kan worden.

Het is bijna niet nodig om zelf Javascript te schrijven, omdat je met Blazor C# kunt schrijven in je pagina’s. Tijdens het project waren er echter wel een paar uitzonderingen waar we via interop toch wat zaken moesten bouwen die niet volledig via de DevExpress componenten ondersteund werden. Dat zal ik verder in dit artikel niet verder toelichten, omdat het te diep gaat voor een eerste introductie.

Server
Het serverproject bevat de code die op de server draait en die de client side voorziet met code van de data via Controllers en Actions. Per razor page op de client is er een aparte Controller, zoals in de gebruikelijke MVC-structuur. De razor page stuurt GET en POST requests naar de server en deze beantwoordt de requests en regelt de afhandeling met bijvoorbeeld de database.

Shared
Dat brengt ons bij het laatste project. Deze bestaat uit de database classes die we via Entity Framework Core gebruiken, inclusief de viewmodels. Classes in dit project worden gebruikt door zowel het client- als het serverproject.

We hanteren aparte viewmodels per controller. Deze zijn vaak nog verder opgesplitst in aparte models voor het inladen van het object (of een lijst van objecten), het toevoegen van een nieuw object en het bewerken van een bestaand object. Voor het verwijderen volstaat in dit project het simpelweg doorgeven van het unieke ID van het desbetreffende object, waardoor geen apart viewmodel nodig is.

Razor pages

Een razor-page gaat terug naar het concept van het begin van .NET waarbij je HTML en C# in één .ASMX-bestand kon combineren. In latere versies werd de scheiding steeds strikter met aparte bestanden voor beide talen, waarbij blazor weer teruggrijpt op dat eerste principe.

Afbeelding 1: Bovenste gedeelte van een Razor pagina

Afbeelding 2: Gedeelte van het einde van een Razor pagina

De meeste pagina’s in dit project hebben de volgende indeling:

  • @page directive
  • @usings en @injects
  • HTML code met DevExpress controls
  • @code sectie

@page
Een .razor bestand dat een zelfstandige pagina is heeft dit directive nodig. Op basis hiervan weet de routing van het project bij welke URL welk component hoort. Een voorbeeld is

@page “/components”

Deze hoort bij de pagina: https://localhost:5001/components. Nog een voorbeeld:

@page “/authentication/{action}”

Deze hoort bij de URL /authentication waarbij de variabele action wordt meegestuurd. Deze variabele kan vervolgens in het @code gedeelte weer gebruikt worden.

@usings en @injects
De @usings zijn net als in een standaard C# class de namespaces die je nodig hebt. De @injects zijn net als in .NET core het client side injecten van classes.

HTML-code met DevExpress controls
In de eerste afbeelding zijn onder andere een DxButton en een DxDataGrid te zien waarmee je heel snel componenten in de pagina kunt opbouwen.

@code sectie
Dit gedeelte regelt alle logica van de pagina of het component, zoals het ontvangen van de gegevens van de server en het versturen van de requests, valideren van data, onderdelen tonen of verbergen, redirecten, etc. Daarover meer in het volgende hoofdstuk.

Dieper de @code in

Het @code blok in dit voorbeeld begint met een OnInitializedAsync() methode. Er zijn een aantal events die afgevuurd worden tijdens de livecycle van een pagina en in de meeste pagina’s gaan we de server om gegevens vragen in deze methode. Ook dit voelt weer heel erg als de oude ASP-wereld, waarbij ook Page_Load() en Page_PreRender() gebruikelijke events waren om je C# code in te schrijven.

In deze pagina doen we een aanroep naar de Components controller via de ingebouwde HttpClient class en het resultaat, een lijst van viewmodels, slaan we op in _components. Het laadicoon dat zichtbaar is zodra de pagina voor het eerste gedeelte gerendered is, wordt verborgen zodra er antwoord terug is van de server. Mocht er een fout optreden laten we de gebruiker dat weten via een toaster, een mededeling die een paar seconden in beeld verschijnt.

De _components is de collectie die het DxDataGrid gebruikt als input en dit component zal voor ieder component een regel gaan afbeelden in het grid.

DxDataGrid

Het DxDataGrid is een heel makkelijke manier om data in een tabel te tonen. Je geeft een lijst van viewmodels mee, geeft aan welke kolommen je wilt zien en eigenlijk doet het component de rest. Pagineren, sorteren, zoeken, filteren, het is slechts een kwestie van een attribuut en het component doet de rest.

Afbeelding 3: Output van het DxDataGrid

Tip!
Denk eraan dat met deze opzet alle componenten worden opgehaald en ingelezen in de browser, met de bijbehorende voor- en nadelen: Pagineren, sorteren en zoeken is snel omdat het niet via de server loopt, maar het wordt problematisch als je te veel gegevens hebt

Gegevens bewerken
In onze opzet worden de gegevens via pop-ups bewerkt. Toevoegen van nieuwe componenten, het bewerken ervan en het verwijderen zijn in aparte pop-ups ondergebracht. In deze applicatie zijn het nooit veel velden, waardoor dat een oplossing is die hier werkbaar is. DxDataGrid ondersteunt ook inline editing, maar daar hebben we in dit project niet voor gekozen.

Het toevoegen van een nieuw component werkt door een POST of PUT te doen via dezelfde ingebouwde HttpClient.

Afronding

In een paar hoofdstukken heb je in vogelvlucht kunnen lezen wat de indeling is van een Blazor solution en van een pagina. Je hebt kunnen zien hoe DevExpress met weinig code mooie, strakke componenten kan genereren met veel functionaliteit die ook nog makkelijk te configureren zijn. In een toekomstig artikel hopen we in te zoomen op een van de onderdelen en zo meer te laten zien van de mogelijkheden van .NET 5.0, Blazor of DevExpress.

Reacties

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.

Dit is een verplicht veld
Dit is een verplicht veld
Geef een geldig e-mailadres op.