Condividi tramite


ASP.NET Core: Introduzione allo sviluppo con Blazor (it-IT)

Introduzione

Blazor è un framework per applicazioni .NET basate su browser, quindi client-side, eseguite tramite WebAssembly. La nuova tecnologia si basa in parte sul gia noto Razor, la sintassi ASP.NET utilizzata per creare pagine dinamiche mediante C# o VisualBasic.NET. Sebbene si tratti di un progetto ancora in fase di sviluppo (e come tale ancora sconsigliata per ambienti di produzione), Blazor si pone l'ambizioso obiettivo di rappresentare un'alternativa a Javascript, permettendo agli sviluppatori .NET un riutilizzo pressochè totale delle proprie competenze. In questo articolo vedremo un esempio introduttivo all'utilizzo di Blazor. Non ci soffermeremo particolarmente sulla sintassi C#, dando per scontato che il lettore possieda una conoscenza di base del linguaggio, ma piuttosto andremo ad analizzare i punti di congiunzione tra la parte .NET e quella piu specificamente relativa al rendering, quindi HTML e CSS.

Prerequisiti

Per l'utilizzo di Blazor in Visual Studio, sono necessari i seguenti prerequisiti

Completati questi passaggi, se tutto è andato a buon fine, durante la creazione di un nuovo progetto ASP.NET Core avremo la possibilita di selezionare due nuovi templates, ovvero "Blazor" e "Blazor (ASP.NET Core hosted)". La differenza tra i due, in termini di definizione, è immediata: il primo viene impiegato per applicazioni a pagina unica (SPA, Single Pages Application), mentre la ASP.NET Core hosted è impiegata per progetti piu articolati, che possono richiedere funzionalità server non disponibili nel primo caso. Dal momento infatti che Blazor va a configurarsi come client-side, se desiderassimo accedere ad una base dati (per esempio tramite Entity Framework) necessiteremmo obbligatoriamente di una componente server relativa al modello del database ed ai controller che rendono disponibili le API di lettura e scrittura della base dati.

In questa sede, volendo presentare Blazor senza coprirne ogni aspetto ad oggi disponibile, ci occuperemo del primo caso, ovvero di un progetto esclusivamente client-side, lasciando per un prossimo appuntamento discorsi che coinvolgano piu tecnologie server-side.

Creazione di un nuovo progetto

Come detto poco sopra, per accedere ai templates di Blazor è necessario creare un nuovo progetto ASP.NET Core

Dopo aver dato un nome al progetto, selezioniamo quindi "Blazor" dal wizard di selezione templates, e confermiamo. E necessario verificare che la versione di piattaforma selezionata sia .NET Core, facendo uso di ASP.NET Core 2.1. Procediamo, e Visual Studio preparerà un progetto con alcune pagine di esempio: si tratta di codice molto immediato ma utile a considerare le meccaniche attraverso cui il codice C# viene ad essere interpretato come linguaggio client-side nella manipolazione della pagina stessa, ed è senz'altro utile consultarlo in prima battuta.

Come si noterà, vi sono principalmente due folder, ovvero "Pages" e "Shared". Gli elementi di quest'ultima realizzano il layout della nostra applicazione, creando una barra superiore ed una laterale, piu un corpo centrale in cui renderizzare le sottopagine via via richiamate. Le visualizzazioni Razor presenti invece nella cartella "Pages" sono i veri e propri "applicativi", ovvero pagine che realizzano diverse funzioni tramite il richiamo a codice C#.

Si noti inoltre, sotto la directory "wwwroot", la possibilita di accedere per esempio agli stili della web application. Espandendo tale punto, ci rendiamo conto di come Blazor sia basato su Bootstrap per la parte CSS, con tutti i relativi vantaggi in termini di responsività, customizzazione, ecc. Ovviamente, nulla vieta di andare a modificare con la propria libreria di preferenza, se diversa.

A questo punto è gia possibile eseguire l'applicazione cosi predisposta, e andare appunto a verificare le sezioni dimostrative.

Tale esplorazione è lasciata alla liberta del lettore, in questa sede ci occuperemo invece della stesura di un piccolo progetto, appena leggermente piu complesso di quelli generati in fase di creazione, ma utile a verificare come le potenzialita .NET possano essere sfruttate in sostituzione dello scripting finora in auge.

Breve nota sul routing delle pagine

Trattandosi di applicazioni web, naturalmente i progetti sviluppati con Blazor dovranno essere eseguiti tramite server web, come ad esempio IIS. Pertanto, per fare in modo che i vari percorsi del sito siano fruibili all'utente, è necessario predisporre le opportune route, ovvero degli URL parziali che identifichino al server l'indirizzo virtuale di una data pagina fisica. Vediamo un breve esempio.

Nel nostro progetto, abbiamo una pagina di nome "counter". Tra i nostri sorgenti abbiamo una visualizzazione di nome "Counter.cshtml", che risiede in una cartella di nome "Pages". Le due sono palesemente collegate, ma come può sapere il web server che al richiamo dell'URL "/counter" debba essere eseguito il rendering di "Pages/Counter.cshtml"? Con una semplice istruzione, posta all'interno di quest'ultima: come infatti noteremo, la prima istruzione di Counter.cshtml è

@page "/counter"

Il routing è conseguentemente molto semplice da implementare.

Il codice che renderizza la sidebar dell'applicazione è contenuto nel file "Shared/NavMenu.cshtml". Qui inseriremo un punto di menu aggiuntivo, che richiamerà la pagina che andremo a realizzare tra poco. 

Si noti tra questi punti il link a "/counter", percorso di routing visto poco sopra. Anche per la nuova pagina dovremo pertanto ideare un percorso di routing, ed istruire la pagina corrispondente al suo utilizzo.

<ul class="nav flex-column">
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="/" Match=NavLinkMatch.All>
            <span class="oi oi-home" aria-hidden="true"></span> Home
        </NavLink>
    </li>
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="/counter">
            <span class="oi oi-plus" aria-hidden="true"></span> Counter
        </NavLink>
    </li>
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="/fetchdata">
            <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
        </NavLink>
    </li>
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="/esempio01">
            <span class="oi oi-list-rich" aria-hidden="true"></span> Esempio01
        </NavLink>
    </li>
</ul>

    

In questo caso, abbiamo semplicemente aggiunto un tag li, nel quale è ora presente il link per navigare verso il percorso "/esempio01".

Sviluppo della Single Page Application

Veniamo ora alla realizzazione dell'esempio.

Creazione della pagina e sua struttura

Nella cartella "Pages", premiamo il tasto destro del mouse e selezioniamo "Aggiungi", quindi "Nuovo elemento", selezionando poi "Visualizzazione Razor". Nel caso in esempio, tale nuovo elemento è stato denominato "Esempio01.cshtml". Vediamo nella prossima immagine la sua struttura di base:

La prima riga è costituita dalla già citata istruzione di routing. A seguire, possiamo inserire qualsiasi tag HTML, ed infine è presente l'istruzione @functions, delimitata da parentesi graffe, all'interno della quale inserire il codice C# che realizzerà le funzioni di interesse. L'alternanza tra codice e HTML sara in funzione alla necessita di utilizzare le variabili del primo all'interno del secondo: una frase forse confusionaria che chiariremo tra un attimo.

Dichiarazioni variabili e loro visualizzazione

Partiamo da un caso banale. Inizializziamo una variabile numerica, e mostriamone il contenuto a video.

Consideriamo quindi questo snippet:

@page  "/esempio01"
 
<h1>Esempio 01</h1>
 
<p>Valore della variabile numero: @numero</p>
 
@functions{
 
    int numero = 5;
 
}

Eseguendo la nostra applicazione, e cliccando sul nuovo punto di menu implementato, noteremo come effettivamente il paragrafo HTML inserito riporti la dicitura "Valore della variabile numero: 5".

Notiamo quindi due aspetti importanti: in primis, che all'interno della sezione @functions è possibile dichiarare variabili in modo classico, le quali saranno visibili in tutta la pagina. Il secondo punto è che tali variabili possono essere richiamate semplicemente interrompendo la parte HTML con il simbolo @. Cio che segue tale simbolo, è considerato codice, e quindi eseguito di conseguenza.

Metodi sottoponibili ad override

Nella sezione @functions notiamo come esistano funzioni sottoponibili ad override. Al momento della stesura di questo articolo, le possibilita offerte sono quelle di figura, rappresentanti eventi relativi allo stato della pagina: si puo intercettare per esempio il momento di inizializzazione della pagina, in maniera sincrona o asincrona, il momento in cui la pagina termina il rendering, e cosi via. Nel prossimo esempio, in cui introdurremo una leggera complessita aggiuntiva, faremo uso del metodo OnInit(), in quanto ci interessera preparare dei dati all'avvio della pagina.

Classi personalizzate e cicli iterativi

Veniamo quindi ad un esempio piu elaborato: in questo caso, realizzeremo la classe personalizzata Persona, per poi andare a popolare una lista di oggetti di tale tipo, e quindi ad esporla.

Consideriamo il seguente codice:

@page  "/esempio01"
 
<h1>Esempio 01</h1>
 
<table class="table">
    <thead>
        <th>Cognome</th>
        <th>Nome</th>
        <th>Eta</th>
        <th>Occupazione</th>
    </thead>
    <tbody>
        @foreach(var persona in lista)
        {
            <tr>
                <td>@persona.Cognome</td>
                <td>@persona.Nome</td>
                <td>@persona.Eta</td>
                <td>@persona.Occupazione</td>
            </tr>
        }
    </tbody>
</table>
 
@functions{
 
    class Persona
    {
        public string Cognome { get;  set; }
        public string Nome {  get; set; }
        public int Eta {  get; set; }
        public string Occupazione { get;  set; }
    }
 
    List<Persona> lista = new List<Persona>();
 
    protected override  void OnInit()
    {
        lista.Add(new Persona() { Cognome = "Rossi", Nome = "Mario", Eta = 40, Occupazione =  "Sviluppatore" });
        lista.Add(new Persona() { Cognome = "Verdi", Nome = "Giuseppe", Eta = 45, Occupazione =  "Analista" });
        lista.Add(new Persona() { Cognome = "Neri", Nome = "Carlo", Eta = 32, Occupazione =  "Addetto marketing" });
    }
}

Come si noterà, nella sezione @functions viene dichiarata la classe Persona, con le sue proprieta. Viene inoltre inizializzata una variabile di nome lista, di tipo List<Persona>, destinata cioc a contenere un elenco di oggetti Persona. Infine, come anticipato sopra, viene eseguito l'override di OnInit, in modo da intercettare l'inizializzazione della pagina e poter quindi popolare la variabile lista con alcuni oggetti. Si noti come il tutto segua la sintassi standard C#, senza necessita di adeguamenti relativi all'ambito di esecuzione web.

Anche la parte HTML è molto semplice: qui si è creata una tabella, indicando quattro colonne per esporre le relative proprieta di classe. Mediante un ciclo foreach (si noti la presenza del carattere @ ogni qualvolta ci si rifa a codice C#), viene iterata la lista, ed eseguito l'accesso alle proprieta di ciascun oggetto per aggiungere alla tabella una riga con le informazioni dell'elemento di ciclo.

Binding delle proprieta ai controlli

Altro punto fondamentale e possibilita offerta da Blazor, è il binding delle proprieta degli oggetti ai controlli a video. Viene cioc fornita, per i controlli che possano supportarla, la parola chiave "bind", mendiante la quale legare variabile e controllo, di modo che la modifica di uno dei due si rifletta sull'altra.

Partendo dall'esempio di cui sopra, inseriamo un'implementazione per capire meglio questo concetto.

Aggiungiamo l'inizializzazione di un oggetto di tipo Persona, al quale, nel metodo OnInit, faremo referenziare il primo oggetto di lista. Detto in altri termini, non avremo una copia speculare della variabile, ma faremo accesso all'elemento zero della lista stessa. Il codice che inseriremo in @functions sara pertanto il seguente:

class Persona
{
    public string Cognome { get;  set; }
    public string Nome {  get; set; }
    public int Eta {  get; set; }
    public string Occupazione { get;  set; }
}
 
List<Persona> lista = new List<Persona>();
 
Persona p = new Persona();
 
protected override  void OnInit()
{
    lista.Add(new Persona() { Cognome = "Rossi", Nome = "Mario", Eta = 40, Occupazione =  "Sviluppatore" });
    lista.Add(new Persona() { Cognome = "Verdi", Nome = "Giuseppe", Eta = 45, Occupazione =  "Analista" });
    lista.Add(new Persona() { Cognome = "Neri", Nome = "Carlo", Eta = 32, Occupazione =  "Addetto marketing" });
 
    p = lista[0];
}

Andiamo ora a modificare la parte HTML: in coda alla tabella, inseriremo un richiamo ad alcune proprieta del nuovo oggetto p:

<label>@(p.Cognome + " " + p.Nome):</label>
<input type ="number" bind="@p.Eta"/>

Notiamo qui altri punti interessanti: nella label creata, si è voluta rappresentare la concatenazione di variabili cognome + nome. Ciò è stato realizzato indicando il simbolo @ seguito da una coppia di parentesi: al loro interno, viene quindi inserito il codice C# che concatena le variabili stringa Cognome e Nome dell'oggetto p, separandole con una spazio. E possibile inserire in questo modo qualsiasi tipo di costrutto, e ne vedremo a breve un altro esempio.

In seconda battuta, notiamo come per il controllo input creato subito dopo sia stato specificato l'attributo bind, ed a questo sia stato passato il valore della proprieta Eta di p. Questa istruzione ci permettera variando il contenuto del campo input, di modificare il valore reale della variabile. Eseguendo l'applicazione, possiamo apprezzare le ricadute pratiche del binding.

Cosa accade alla modifica del valore contenuto nella casella di testo? Verifichiamolo:

Come si noterà, abbassando il valore della proprietà Eta di p, questa viene aggiornata anche nella corrispondente riga di tabella, in quando referenza del primo oggetto presente nella lista. Possediamo quindi uno strumento potentissimo per accedere alla struttura della pagina stessa ed ai dati elaborati, e modificarli con risultati visibili in tempo reale.

Costrutti condizionali e modifiche in tempo reale

Sulla base di quanto visto nel punto precedente, apportiamo un'ulteriore modifica al nostro codice. Supponiamo di voler disporre di un avviso grafico di qualche tipo, che ci dia un colpo d'occhio su quegli oggetti la cui proprieta Eta supera il valore di 50. In questo caso, modificheremo soltanto la parte HTML, aggiungendo un costrutto condizionale C# per mostrare come sia possibile concatenare piu istruzioni anche di natura diversa dalla semplice assegnazione.

Consideriamo questo ultimo snippet:

<table class="table">
    <thead>
        <th>Cognome</th>
        <th>Nome</th>
        <th>Eta</th>
        <th>Occupazione</th>
        <th>Verifica</th>
    </thead>
    <tbody>
        @foreach(var persona in lista)
        {
            <tr>
                <td>@persona.Cognome</td>
                <td>@persona.Nome</td>
                <td>@persona.Eta</td>
                <td>@persona.Occupazione</td>
                <td style="background-color: @(persona.Eta > 50 ? "red": "lightgreen")"> </td>
            </tr>
        }
    </tbody>
</table>

Si noti cioè la presenza di una ulteriore colonna, di intestazione "Verifica". Nella sua cella di riferimento, si accede al suo attributo style per modificarne il valore di background-color, proprietà che definisce il colore di sfondo. Con il simbolo @ dichiariamo ancora una volta la presenza di codice, e scriviamo quindi la condizione che verifica se la proprietà Eta dell'oggetto persona è maggiore di 50: in caso affermativo, emetteremo il testo "red", viceversa "lightgreen": queste due stringhe fungeranno da valore per background-color, ovvero produrranno colorazioni di sfondo differenti a seconda dell'esito del test.

Vediamo quindi in esecuzione, digitando il valore di 60 nella casella eta di Rossi Mario, cosa accade:

Conclusione

Abbiamo visto come, sebbene nelle sue fasi iniziali, Blazor rappresenti una innovazione tutt'altro che trascurabile. L'adozione del .NET Framework mediante WebAssembly su web mette in condizione di poter utilizzare le proprie competenze .NET per sviluppare, risultando in una curva di apprendimento molto rapida e dando la sensazione di trovarsi appieno in un ambito noto. Trovandoci poi a lavorare completamente con tecnologie Microsoft, risulter? altres? semplice interfacciarsi con basi dati e sfruttare API scritte all'occasione. In sintesi, un progetto per il quale sperare una crescita continua, rappresentando un prezioso strumento per la propria produttività.

Codice dimostrativo

Il codice sorgente realizzato nell'articolo è liberamente scaricabile al seguente indirizzo: https://code.msdn.microsoft.com/ASPNET-Core-Introduzione-48b42019

Bibliografia