Aurelia e ASP.NET Core: binding di base in Aurelia

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Al termine del post precedente ci eravamo lasciati con la necessità di idratare la nostra View con i dati provenienti dal ViewModel utilizzando un meccanismo detto binding. Vediamo quindi quali strumenti Aurelia ci mette a disposizione per gestire questa operazione.

Attribute binding, event binding e string interpolation

Riprendiamo quindi il nostro template e vediamo in che modo dobbiamo modificarlo per aggiungere la sintassi relativa al binding caratteristica di Aurelia:

Cominciamo da title (1) e master (2) per i quali utilizzeremo la string interpolation. Come suggerisce il nome, si tratta di una sintassi particolarmente utile nelle situazioni in cui si voglia usare testo dinamico proveniente dal ViewModel eventualmente insieme a testo statico inserito direttamente nella View. Non sorprenderà che Aurelia gestisca questo scenario facendo riferimento agli standard ES2015 per la string interpolation, cioè con la sintassi ${expression} in cui expression è una qualsiasi espressione JavaScript. Ad esempio <div>static text ${game.description} more static text </div> per inserire il valore della proprietà description in un div intercalandolo con del testo statico. Nel nostro caso avremo quindi:

Passiamo al button per unirsi ad una partita (3) e al link per partecipare ad una sessione di gioco (4). In questo caso abbiamo due problemi da risolvere: dobbiamo rendere visibili i due elementi a seconda del valore delle proprietà canJoin e canPlay, e dobbiamo eseguire il metodo join in seguito al click sul button. Per risolverli useremo le altre due sintassi previste da Aurelia, attribute ed event binding, più un'altra particolarità estremamente flessibile e potente di Aurelia: i custom attribute.

L'attribute binding è caratterizzato dalla sintassi attribute.command="expression". Dato un qualunque attributo (attribute), è possibile valorizzarlo con in risultato di un'espressione JavaScript (expression) attraverso l'applicazione di uno tra i comandi supportati (command). Approfondiremo il concetto dei comandi (che servono per definire direzione e frequenza degli aggiornamenti) in un prossimo post, per ora accontentiamoci di usare il comando generico bind che determina in maniera intelligente il tipo di comando specifico da applicare (con una modalità detta binding adattativo che è caratteristica di Aurelia). Potremmo ad esempio scrivere <a href.bind="game.url">Vai alla partita</a>. per utilizzare il contenuto della proprietà url come destinazione del link Vai alla partita.

Nel nostro caso abbiamo però un altro problema. In HTML5 non esiste (ovviamente) un attributo specifico che specifichi se vogliamo includere o meno un certo elemento nel DOM della pagina. Essendo una questione centrale in un'applicazione SPA, ogni framework che si rispetti ha dovuto affrontarla e risolverla. Invece di inventare una sintassi proprietaria (e magari astrusa) come per altri framework, Aurelia cerca come al solito di rimanere il più possibile aderente alle specifiche HTML5 e mette a disposizione degli attributi custom con cui poter decorare gli elementi del DOM per ottenere comportamenti personalizzati. Non solo Aurelia è fornito di alcuni custom attribute out-of-the-box, ma ci mette a disposizione l'architettura per poterne definire a nostra volta con una semplicità disarmante. Per oggi però non affronteremo questo tema ma ci limiteremo ad usare due di questi attributi builtin. Il primo è l'if è serve appunto a discriminare la presenza o meno di un elemento nel DOM a seconda dell'espressione utilizzata nel bind. In breve <div if.bind="expression"> rende il div parte della pagina o meno a seconda del risultato di expression.

Risolto il problema della visibilità, passiamo all'esecuzione del metodo join. In questo caso di tratta di reagire ad un evento del DOM per invocare un metodo del ViewModel. Per questo scenario Aurelia mette a disposizione l'event binding.

L'event binding sfrutta la stessa sintassi dell'attribute binding per consentirci di intercettare gli eventi che vengono lanciati dagli elementi del DOM. Le uniche differenze sono nei comandi supportati (trigger e delegate per l'event binding) e nella proprietà speciale $event che può essere usata nell'espressione JavaScript per ottenere un riferimento al DOM event originale. Anche in questo caso rimandiamo l'approfondimento dei due comandi, utilizzando al momento il delegate in maniera del tutto fideistica. Ad esempio <button click.delegate="run()">Esegui</button> per eseguire il metodo run in risposta al click sul button Esegui. Nel nostro caso quindi:

L'ultima cosa che ci resta da fare per completare la "tile" della partita è colorare il panel di verde o di rosso. Si tratta in questo caso di aggiungere il class panel-success o quello panel-danger al div che definisce la "tile" (cioè quello con class panel). Per farlo useremo ancora una volta la string interpolation utilizzando in questo caso un'espressione:

Ora che il frammento di HTML che descrive la partita è completo, non ci resta che iterare tutti gli elementi che compongono il nostro array e clonare il frammento iniettandolo di volta in volta nel DOM. Come già detto nel caso della visibilità, HTML non fornisce ovviamente un supporto nativo per questo scenario; non esiste quindi un attributo o un tag specifico per gestire questa operazione. Ecco che arriva in nostro soccorso il secondo custom attribute cui facevo riferimento in precedenza. Si tratta del repeat.for, per mezzo del quale possiamo indicare al framework una collezione su cui vogliamo iterare usando (manco a dirlo) la sintassi standard di ES2015 per il comando for, ossia item of collection. Aurelia prende automaticamente l'elemento del DOM su cui abbiamo apposto l'attributo come template per i vari elementi della lista e si occupa di clonare e iniettare nel DOM l'HTML risultante. In definitiva:

Non ci resta che il button che determina la creazione di una nuova partita. Anche in questo caso possiamo usare l'event binding scrivendo:

Prima di poter eseguire il nostro codice c'è un'altra operazione che dobbiamo portare a termine. Nello screenshot del post precedente abbiamo visto che ho utilizzato Bootstrap per migliorare un po' (nei limiti imposti dalla mia incompetenza di grafico) il look dell'applicazione. In primis dobbiamo quindi importare il relativo package da JSPM seguendo la procedura già descritta per i package di Aurelia. Fatto ciò dobbiamo fare in modo che il css di Bootstrap sia caricato insieme alla nostra applicazione. Possiamo ottenere questo risultato in tre modi:

  1. Aggiungendo un tag link che punti al css nella pagina principale index.html in modo che sia caricato non appena atterriamo sull'entry point della nostra applicazione:
  2. Usando un tag require che punti al css all'interno della nostra View app.html in modo da comunicare ad Aurelia (e quindi a JSPM) che abbiamo bisogno di quel file e che deve essere dinamicamente caricato (se non è già stato fatto):
  3. Specificando il css come risorsa globale durante la configurazione di Aurelia:

Trattandosi di una risorsa non specifica della View, ma piuttosto necessaria a livello di intera applicazione, la soluzione ideale sarebbe la terza (in realtà ci sarebbe anche una quarta opzione ma non facciamo confusione al momento). Visto però che non abbiamo ancora approfondito la configurazione, andrò per ora con la seconda soluzione.

Ed ora, F5 e via!

Prima di concludere voglio spendere due parole sul frammento di HTML che abbiamo usato come template della partita. Abbiamo visto in un post precedente che ogni View in Aurelia è un template HTML5 introdotto dall'apposito tag template. Nulla ci vieta, e anzi in alcuni casi prossimamente useremo proprio questo approccio, di estrarre il div che descrive la partita in un file esterno, strutturato a sua volta come template HTML5 (cioè incorporato in un tag template). A questo punto possiamo istruire Aurelia ad usare quel template per popolare la parte di pagina relativa alla partita, potendo allo stesso tempo riusare lo stesso file in altre pagine in cui abbiamo bisogno della stessa UI (con un meccanismo in parte simile a quello delle partial view di MVC). Questo meccanismo è detto in Aurelia composition e, come vedremo in un prossimo post, consente di comporre la propria pagina con un alto grado di flessibilità.

Happy coding!

P.S. Il codice sorgente è disponibile su GitHub, basta scaricare la release con lo stesso nome del post (Binding di base in questo caso).

Aurelia e ASP.NET Core: fondamenti di binding

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Se fino ad oggi abbiamo navigato sotto costa, è arrivato il momento di rompere gli indugi e puntare la prua al largo. Nel proseguo della nostra esplorazione dell'universo Aurelia proverò a costruire un'applicazione concreta, per evitare di cadere nel solito tranello delle presentazioni apparentemente perfette che poi crollano al primo caso reale. Io realizzerò un'applicazione per supportare on-line un gioco di ruolo, voi potete ovviamente seguire la stessa strada o realizzare qualcosa di diverso.

I requisiti della nostra applicazione

Prima di buttarci nel codice, devo necessariamente spendere due parole per chiarire il dominio applicativo: per chi non lo sapesse un gioco di ruolo è quello in cui una serie di giocatori si calano nella parte di personaggi immaginari e vivono le avventure (generalmente in stile fantasy) narrate da un altro giocatore, detto master, che rappresenta il deus ex-machina della storia. Nel mio caso sto parlando del GdR "originale", in cui i giocatori si riuniscono attorno ad un tavolo e il master racconta la storia e dipana le vicende. Si dà però il caso che nel frattempo i giocatori hanno messo su famiglia e non possono più vedersi con la facilità di prima. Urge quindi trasformare le sessioni reali in sessioni virtuali (su Skype) e urge un supporto informatico per tenere traccia dell'evoluzione dei personaggi (l'equivalente digitale della scheda cartacea).

Ora che abbiamo chiaro il contesto, vediamo quali sono i primi requisiti dell'applicazione:

  • Come ospite, voglio diventare membro della community per poter giocare;
  • Come membro, voglio autenticarmi per poter accedere ai miei dati e alle mie partite;
  • Come utente, voglio vedere la lista delle partite cui sto partecipando;
  • Come utente, voglio iniziare una nuova partita come master;
  • Come utente, voglio unirmi ad una partita in corso come giocatore.

Cominciare gli sviluppi dai primi due requisiti, oltre che essere tremendamente noioso, ci obbligherebbe ad un nuovo percorso teorico di studio delle modalità di autenticazione/autorizzazione di una SPA, tenendo anche conto che non ho alcuna intenzione di gestire registrazioni, nomi utenti e password ma voglio invece sfruttare i servizi offerti dai principali provider di autenticazione (Facebook, Google, Microsoft, …). Dato che vogliamo fermamente mettere un primo abbozzo dell'applicazione sotto l'albero di Natale, daremo i primi due requisiti per acquisiti e cominceremo a sviluppare dal terzo.

Per iniziare assumiamo quindi di avere un utente registrato ed autenticato che nella sua home page voglia: a) vedere la lista delle partite cui è coinvolto; b) dare inizio ad una nuova partita e c) unirsi ad una partita in corso.

Per quanto detto fino adesso, dovrebbe essere ormai chiaro che un'applicazione Aurelia si compone di due componenti: la View, che contiene il template grafico da utilizzare, e il ViewModel, che contiene i dati con cui idratare tale template per comporre la pagina finale. Un'ipotetica pagina di visualizzazione di un utente, ad esempio, avrà un certo template grafico (sempre uguale) che sarà poi riempito di volta in volta con i dati specifici del particolare utente.

Nel nostro caso, come prima cosa abbiamo quindi bisogno di un file JavaScript che conterrà le informazioni sulle partite, e di un file HTML che avrà lo scheletro della UI da far vedere all'utente. Abbiamo visto che per convenzione Aurelia carica una pagina che corrisponde alla coppia app.js/app.html. Non ci vogliamo ancora addentrare nei gorghi della configurazione, quindi per ora ci limiteremo a riusare gli stessi due file dell'esempio precedente, semplicemente aggiornandone il contenuto.

Il primo ViewModel

Se vogliamo mostrare un elenco di partite, un buon punto di partenza è avere un array contenente i dati delle stesse. In futuro tali dati arriveranno da una chiamata ad un apposito servizio ASP.NET Core, per il momento è più che sufficiente dichiarare un array hard-coded nel costruttore della classe che rappresenta il nostro ViewModel usando la sintassi ES2015:

Cominciamo con il descrivere una partita con un modello molto semplice che arricchiremo nel corso del tempo: Un identificativo univoco della partita (id), il nome della stessa (title), il nome del giocatore che svolge le funzioni di master (master) e due flag che ci dicono se possiamo unirci (canJoin) o se possiamo partecipare alla sessione di gioco corrente (canPlay).

Come vedete non c'è alcun obbligo di chiamare la classe con lo stesso nome del file (anche se è buona norma per i ViewModel per non generare confusione). Dato che già so che "a regime" la nostra coppia si chiamerà games.js/games.html, ho chiamato la classe direttamente Games.

Oltre ai dati sulle partite esistenti, per soddisfare gli ultimi due requisiti abbiamo bisogno dei due metodi per creare una nuova partita e per unirsi ad una partita esistente. Anche in questo caso ci limitiamo momentaneamente a due metodi fake con il solo scopo di verificare il funzionamento della pagina:

La prima View

Per capire come definire il template diamo prima un'occhiata al risultato finale che vogliamo ottenere:

Vogliamo quindi un panel bootstrap per ogni partita, il cui header sarà uguale al nome della partita (title) e il cui body riporterà il nome del master (master). Un button sempre nel body ci consentirà di unirsi alla partita (canJoin = true) o di accedere alla stessa (canPlay = true), mentre un altro button fuori dall'elenco permetterà di creare una nuova partita. Le partite "giocabili" saranno evidenziate in verde, le altre in rosso. Il frammento di HTML necessario ad ottenere il risultato di cui sopra (al netto delle informazioni sulle singole partite) è questo:

In questa porzione di HTML dobbiamo inserire il title (1) e il master (2). Dobbiamo inoltre fare in modo che il button (3) sia visibile solo se canJoin = true e che il suo click esegua il metodo join del ViewModel e che il link (4) sia invece visibile se canPlay = true. A seconda del valore di canPlay dobbiamo quindi aggiungere il class panel-success o quello panel-danger al panel (5). Tutto ciò va ovviamente ripetuto per ogni partita del nostro elenco duplicando l'intero div (6). Infine dobbiamo chiamare il metodo create del ViewModel al click sul button (7).

Cos'è il binding?

Il problema diventa quindi quale meccanismo utilizzare per gestire questo travaso di dati dal ViewModel alla View.

L'approccio più semplice è ovviamente dato da un'interazione "forte" tra le due parti. Il ViewModel conosce perfettamente la struttura della View ed è in grado di individuare le parti che devono essere idratate e di iniettare nelle stesse i valori presenti al suo interno (ad esempio utilizzando jQuery con una sintassi tipo $('#title').html(this.title). Questa operazione può essere tipicamente portata a termine al momento del caricamento, fornendo all'utente una pagina già completa di tutte le informazioni.

Le cose però si complicano quando dobbiamo gestire la visibilità di alcuni elementi o quando dobbiamo gestire una lista con la conseguente necessità di clonare e iniettare nuove porzioni di HTML. Ancor peggio quando il passaggio delle informazioni deve essere bidirezionale, quando cioè le informazioni aggiornate dall'utente sulla View devono essere ritrasmesse al ViewModel, tipicamente per dare avvio ad un processo di business o ad una semplice operazione di salvataggio delle stesse. Nasce infatti l'esigenza di individuare il momento in cui riportare le informazioni sul ViewModel, intercettando una serie di eventi sulla pagina (come il click sul pulsante di submit o la digitazione in un campo di input), e in breve tempo la gestione di questi scambi di dati può diventare molto complessa e tremendamente fragile per via dello stretto collegamento tra le due parti che costringe a tenere allineato il ViewModel ad ogni cambiamento della View.

Per ovviare a questa serie di problematiche, i framework che si basano sul pattern MVVM (come Aurelia) utilizzano un meccanismo detto binding. In cosa consiste? In parole povere si tratta di una sintassi specifica che consente di specificare all'interno della View i punti in cui è necessaria l'interazione con un corrispettivo elemento del ViewModel, che sia il valore di una proprietà che deve essere riportato sulla UI, un metodo che deve essere invocato al click di un pulsante o ancora un flag che determina la visibilità o meno di un elemento grafico. La sintassi è ovviamente riconosciuta dal framework che è quindi in grado di processare la View, individuare i punti di interazione e idratare la UI con i valori provenienti dal ViewModel. In aggiunta il framework si prende anche carico della successiva gestione della vita della View, intercettando gli eventi scatenati dall'interazione dell'utente, modificando il ViewModel e di riflesso aggiornando ulteriormente la View stessa. Tutto ciò potendo mantenere il ViewModel del tutto agnostico rispetto alla View.

Nel prossimo post vedremo quali strumenti Aurelia ci mette a disposizione per gestire il binding.

Merry coding and happy new year!

Aurelia e ASP.NET Core: convention-over-configuration

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Al termine di un precedente post ci eravamo lasciati con tre domande cui stiamo rispondendo prima di procedere.

Come ha fatto Aurelia a capire che volevamo mostrare il contenuto della pagina app?

Nel primo post di questa serie avevamo accennato al fatto che Aurelia è fortemente basato sul concetto di convention-over-configuration. Di che si tratta? In termini estremamente semplici l'idea si può così riassumere: in una qualsiasi applicazione (sia essa basata su SPA come in Aurelia o su un altro approccio, tipo MVC) ci troviamo costantemente ad affrontare problemi architetturali generici e comuni, come ad esempio banalmente, in che modo registriamo sul framework i componenti che vogliamo includere? E in che modo gli comunichiamo l'associazione tra una View e il suo ViewModel? Alcuni framework sono molto cerimoniosi da questo punto di vista e richiedono lunghe configurazioni che a volte trascendono nella puntualizzazione dell'ovvio. Aurelia, come altri framework basati sullo stesso concetto, cerca invece di "supporre" in maniera intelligente quello che potremmo aver necessità di fare applicando in autonomia una serie di convenzioni tratte dall'esperienza. Che succede se abbiamo esigenze specifiche che mal si conciliano con le convenzioni definite da Aurelia? Nessun problema, possiamo facilmente esplicitare una diversa configurazione e Aurelia ne terrà conto (ma vi assicuro che le convenzioni di Aurelia sono assolutamente sensate e logiche).

Già nel nostro primo semplicissimo esempio ci siamo imbattuti in questo approccio, e ancora avremo modo di farlo proseguendo nel nostro viaggio. Cosa è successo dietro le quinte che ha consentito alla pagina app di essere mostrata senza una nostra specifica indicazione? Cogliamo l'occasione per familiarizzare con il codice di Aurelia e addentriamoci nel framework per risolvere il "mistero".

Il codice contenuto nel file index.html è ridotto veramente al minimo. È quindi chiaro che se c'è della magia, questa è contenuta nel bootstrapper che viene caricato con la chiamata System.import('aurelia-bootstrapper').

Potremmo quindi aprire il file aurelia-bootstrapper.js che si trova in wwwroot/_libs/npm/aurelia-bootstrapper@1.0.1 ma ci troveremmo davanti a codice ES5. Il pacchetto presente su NPM e scaricato da JSPM è infatti già convertito in ES5 per garantire la massima compatibilità con i browser attualmente sul mercato. Nulla ci vieta ovviamente di cercare la soluzione qui, ma io andrò invece alla fonte, direttamente su GitHub, dove si trova il file originale in ES2015.

Il file si compone di una serie di variabili statiche e funzioni definite secondo la sintassi ES2015. Nulla di tutto ciò comporta esecuzione di codice al momento del caricamento. Ma se andiamo proprio in fondo al file, troviamo la dichiarazione di una constante starting il cui valore è pari al risultato della chiamata alla funzione run (manco a dirlo un oggetto che rappresenta una promise):

È questa quindi la funzione che viene eseguita immediatamente al caricamento del modulo e che determina l'avvio di Aurelia. Dopo aver eseguito un po' di codice di inizializzazione, la funzione run cerca nel documento i tag (nel nostro caso il body) che abbiamo marcato con l'attributo aurelia-app (ricorderete che nel precedente post avevamo detto che questo attributo serve ad indicare ad Aurelia in quale parte della pagina vogliamo caricare l'applicazione).

A giudicare dal codice sembrerebbe che Aurelia sia in grado di gestire contemporaneamente diverse applicazioni completamenti distinte e indipendenti. Così su due piedi non mi vengono in mente scenari in cui ciò potrebbe essere necessario, in ogni caso è un ulteriore attestato di quella flessibilità del framework che avremo modo di apprezzare più in concreto in altre situazioni. Per ogni attributo trovato viene chiamato il metodo handleApp per gestire l'inizializzazione dell'applicazione:

La funziona handleApp si limita a recuperare il valore dell'attributo aurelia-app e a passarlo alla funzione config che si occupa della configurazione:

Il parametro viene ricevuto dalla funzione config con il nome di configModuleId e memorizzato nella proprietà omonima dell'oggetto Aurelia appena creato. Questo ci fa capire cosa si aspetta Aurelia da quel modulo (nel caso in cui, come avverrà in futuro, decidessimo di specificarne il nome nell'attributo aurelia-app): una classe tramite la quale configurare il framework a nostro piacimento.

In ogni caso, visto che non abbiamo specificato un valore per l'attributo, aurelia.configModuleId sarà null, la porzione di codice subito sottostante sarà ignorata e, al termine della procedura di avvio (cioè nel ramo then della promise ritornata da start), il controllo passerà al metodo setRoot:

Il metodo setRoot è definito all'interno della classe Aurelia che fa parte del package aurelia-framework e si occupa di caricare la prima pagina dell'applicazione. Il metodo si aspetta un parametro opzionale root che di default è null (convention) il che ci fa capire che in altri scenari potremo passare espressamente la pagina che vogliamo sia l'entry point della navigazione (configuration). Visto che nel nostro caso root è null e che this.configModuleId è parimenti null (per quanto visto sopra), il metodo imposta la root ad "app" (convention) e poi la utilizza come primo ViewModel da caricare:

L'arcano è dunque risolto, abbiamo preso confidenza con il codice interno di Aurelia, e abbiamo anche avuto modo di vedere che il modulo che definisce la classe base del framework è scritto in TypeScript (come avrete notato dalla tipizzazione dei parametri e dal generic applicato alla Promise di ritorno).

Le prove tecniche di navigazione sono terminate, dal prossimo post prenderemo il largo sul serio.

Happy coding!

Aurelia e ASP.NET Core: i template di HTML5

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Al termine di un precedente post ci eravamo lasciati con tre domande cui stiamo rispondendo prima di procedere.

Che fine ha fatto il tag template che era nel file app.html?

Nell'esempio del post avevamo creato un semplicissimo file che conteneva un frammento di HTML con un tag template. Nella pagina inviata al browser tale tag era però sparito. Come mai?

Nel primo post di questa serie avevamo detto che Aurelia è stato progetto cercando il massimo rispetto degli standard HTML e ECMAScript esistenti. Quando per il funzionamento del framework c'è bisogno di un costrutto o di una sintassi dedicata, la scelta del Team è stata quella di inventare il meno possibile, riutilizzando se possibile quanto già standardizzato dalle ultime specifiche.

Nel caso delle View (come la pagina app.html del nostro esempio) la scelta è stata quindi l'utilizzo della sintassi HTML5 per i Template. Di cosa si tratta?

Nelle specifiche HTML precedenti alla versione 5 ha sempre spiccato la mancanza di un meccanismo di templating nativo. Stiamo parlando in sostanza dell'equivalente di ciò che è Razor per il mondo ASP.NET o Django per quello Python. L'esigenza è in definitiva quella di inviare al browser un frammento di HTML da non renderizzare direttamente ma da usare come stampo per creare porzioni di pagina più grandi e tipicamente uguali tra loro (a meno ovviamente dei dati specifici di ogni singola componente). Per capire meglio di cosa stiamo parlando, potremmo pensare ad una tabella composta da tante righe, tutte ovviamente uguali per quando attiene a struttura, layout e stili, con la sola differenza delle informazioni riportate in ognuna di esse.

Come detto fino ad oggi le specifiche non prevedevano una soluzione standard per tale necessità, e gli espedienti comunemente più usati (sia dai singoli programmatori che dalle librerie di componenti più diffuse) consistevano nell'incapsulare tali frammenti in tag script marcati con un attributo type personalizzato (come ad esempio <script type="text/x-my-templates">…</script>) o in elementi del DOM nascosti (<div style="display: none">…</div>). In tale modo era possibile poi individuarli, manipolarli e aggiunti alla pagina dinamicamente tramite JavaScript.

Entrambe queste soluzioni sono caratterizzate da limiti e difetti che sono stati fortunatamente superati in HTML5, grazie alla definizione di un nuovo tag dedicato, il template appunto.

Il vantaggio principale del tag template è dato dal fatto che, pur essendo presente sulla pagina, è del tutto inerte fino a quando non viene clonato e iniettato nuovamente nella pagina stessa sotto forma di frammento di HTML. Inerte vuol dire che il contenuto del template non viene processato al momento del caricamento, ma solo al momento della clonazione. Se ad esempio nel contenuto è presente un tag script, il codice JavaScript all'interno dello stesso non viene eseguito se non in fase di clonazione. In quello stesso momento sarà caricata ad esempio l'immagine cui fa riferimento l'attributo src di un eventuale tag img.

Se modificassimo il file app.html del post precedente in questo modo:

e provassimo poi a caricare il file direttamente in un browser pienamente compatibile con le specifiche HTML5 relative ai template (Chrome nel mio caso), potremmo verificare che né il contenuto HTML né il codice JavaScript della pagina vengono eseguiti al momento del caricamento:

Per rinforzare questa separazione tra la pagina e il template, anche i normali meccanismi di ricerca degli elementi del DOM, come l'arcinoto document.getElementById, non funzionano sugli elementi che fanno parte del contenuto del template, in modo da evitare che si possa, anche involontariamente, interagire con esso.

I Template fanno parte di un gruppo di quattro nuove tecnologie definite nelle specifiche di HTML5 (insieme a Custom Element, Shadow DOM e Import) che sono alla base del concetto di Web Component che avremo modo di approfondire più avanti quando parleremo di tecniche avanzate di composizione delle pagine in Aurelia.

Per ora ci basta sapere che tutte le nostre View saranno frammenti di HTML inclusi in un tag template da cui erediteranno proprietà e comportamenti. Al momento opportuno Aurelia si occuperà di recuperare il template, idratarlo con i dati provenienti dal ViewModel e iniettarlo nella posizione corretta del DOM.

Happy coding!

Aurelia e ASP.NET Core: moduli, classi e promise in ES2015

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Al termine dell'ultimo post ci siamo lasciati con tre domande cui cercheremo di rispondere in tre post ravvicinati nei prossimi giorni.

Cos'è la strana sintassi che abbiamo usato nel file app.js?

Nel primo post di questa serie avevamo accennato al fatto che Aurelia è scritto interamente in ES2016, l'ultimissima versione delle specifiche JavaScript che va ulteriormente ad estendere il già innovativo ES2015 (per lungo tempo altrimenti noto come ES6).

Descrivere, anche in modo sommario, tutte le nuove caratteristiche di ES2015/6 ci farebbe deviare troppo dalla nostra rotta. Userò quindi il "solito" approccio di limitarmi a descrivere quello che ci è realmente utile al momento, lasciando eventuali ulteriori approfondimenti ad un prossimo post.

Classi

ES2015 introduce in JavaScript il concetto di classe. Proprio come in C# o in altri linguaggi ad oggetti, una classe è una matrice per creare oggetti: ogni oggetto al momento della creazione sarà fornito degli attributi (proprietà) e dei comportamenti (metodi) definiti nella classe.

Il concetto di oggetto non è ovviamente nuovo in JavaScript ma per via della complessità nella sua gestione a 360 gradi e dell'approccio radicalmente diverso dagli altri linguaggi ad oggetti, le nuove specifiche hanno aggiunto un po' di "syntactic sugar" per mezzo della nuova keyword class. Creare un oggetto in JavaScript è quindi ora molto simile alla sua controparte C#: si definisce una classe e si istanzia l'oggetto sempre usando new. La definizione delle proprietà della classe avviene direttamente all'interno del costruttore mentre i metodi possono essere aggiunti al corpo (FYI ES2016 ha ulteriormente esteso questo nuovo costrutto dando la possibilità di definire anche le proprietà nel corpo della classe, in maniera più simile a quanto facciamo con C#):

Con il nuovo costrutto, l'ereditarietà viene gestita per mezzo della keyword specifica extends:

Ho già avuto modo di dire che si tratta solo di "syntactic sugar". Dietro le quindi il funzionamento è ancora quello di ES5, basato su funzioni e prototype. Ma di questo parleremo magari meglio in un post dedicato, fuori da questa serie su Aurelia. In questo contesto ci basti sapere che questa sarà la sintassi che useremo ogni volta che dovremo definire un ViewModel da associare ad una View. Ma il pur banale ViewModel che abbiamo costruito presentava un'altra keyword "strana": export. Di che si tratta?

Moduli

Da sempre JavaScript soffre di problemi di scarsa organizzazione del codice e mancanza di controllo sulla visibilità dello stesso. Per farla breve:

  • Tutto ciò che viene definito (funzioni, variabili, ecc.) diventa un attributo dell'oggetto globale window il che, oltre a generare una certa confusione, espone le applicazioni a conflitti sui nomi quando si usano librerie provenienti da fonti diverse (che come sappiamo in JavaScript è la norma);
  • Come se non bastasse, tutto il codice scritto è esposto pubblicamente, non c'è modo di definire logiche interne ad un oggetto come facciamo ad esempio con i metodi privati in C#, e la dinamicità del linguaggio (inclusa la possibilità di sostituire il corpo di una funzione con codice completamente diverso a runtime con una semplice assegnazione) non fa che peggiorare le cose;
  • Spesso parti di codice definite in file o librerie diverse dipendono l'una dall'altra e non è sempre immediato garantire che il file che contiene una certa funzione venga caricato prima di quello che la utilizza, causando in qualche occasione eccezioni non previste.

Ovviamente la comunità di sviluppatori JavaScript non è stata semplicemente ferma a subire queste lacune del linguaggio ma ha piuttosto cercato forme alternative per ottenere il risultato desiderato (e come ormai dovrebbe essere chiaro in un linguaggio dinamico come JavaScript c'è quasi sempre un modo, magari non proprio ortodosso, per raggiungere il proprio scopo).

Dopo un primo tentativo di mitigazione tramite le cosidette Immediately-Invoked Function Expression (IIFE), una seconda risposta è arrivata dalle specifiche CommonJS e da quelle AMD (Asyncronous Module Definition) su cui si basa RequireJS. Alla base di questo nuovo approccio ci sono i concetti di modulo come unità indipendente e quelli di esportazione e importazione del contenuto dello stesso per definire i livelli di visibilità e le dipendenze tra i moduli.

ES2015 contribuisce a standardizzare quelle specifiche attraverso l'introduzione di due nuove keyword: export e import appunto. Ogni file JavaScript costruito secondo le specifiche costituisce un modulo a sé stante i cui elementi interni (variabili, funzioni, classi) vivono in isolamento rispetto agli altri moduli e al contesto globale. Gli elementi del modulo (uno o più) che si vogliono rendere pubblici devono essere esplicitamente marcati con la keyword export, come abbiamo fatto nel post precedente nel file app.js, e importati nel modulo che ne vuole usufruire (come si vede dalle "ondine" rosse, Visual Studio 2015 ad oggi non digerisce molto bene la sintassi ES2015 nel file js):

Aurelia si occupa di caricare i moduli che compongono i ViewModel automaticamente quando sia necessario il render della corrispettiva View, quindi tipicamente non avremo bisogno di importare i ViewModel nella nostra applicazione. Avremo invece bisogno di importare i moduli JavaScript che useremo ad esempio per incapsulare il codice di interfacciamento con i nostri servizi di back-end.

Promise

C'è un ultimo aspetto di ES2015 di cui dobbiamo parlare anche se non l'abbiamo incontrato nel primo semplicissimo ViewModel. Aurelia è infatti fortemente basato sulla programmazione asincrona. La quasi totalità delle funzioni del framework è progettata per ritornare immediatamente il controllo al chiamante mentre prosegue l'esecuzione delle operazioni, salvo poi notificare il completamento delle stesse a tempo debito.

Il concetto di programmazione asincrona è ben noto agli sviluppatori web per via della latenza intrinseca nell'architettura client/server basata su HTTP. Ogni volta che comunichiamo con il server per ottenere delle informazioni, non possiamo fare assunzioni sui tempi di risposta e quindi, se non vogliamo bloccare completamente l'esecuzione dell'applicazione, è buona norma tenere conto di queste limitazioni e progettarla di conseguenza.

Il modo "tradizionale" di gestire la programmazione asincrona in JavaScript (e non solo) era basato sul meccanismo delle callback. Una funzione che doveva eseguire operazioni potenzialmente molto lunghe prevedeva tra i propri parametri una funzione da chiamare al termine delle operazioni. In questo modo era possibile ritornare immediatamente il controllo al chiamante ed eseguire poi il codice in risposta al completamento nella funzione di callback.

Non mi dilungherò sui tanti problemi che questo comporta. Trovate tonnellate di documentazione in rete (tra cui ad esempio le slide della mia sessione a .NET Campus). In ogni caso per superare tali limitazioni già da diversi anni si è diffuso l'utilizzo delle promise come alternativa alle callback.

Anche in questo caso infatti, come per le classi e i moduli, ES2015 arriva a standardizzare un approccio già in voga tra gli sviluppatori, con diverse librerie che fornivano un'implementazione delle specifiche Promises/A+ come ad esempio Q.

Una promise è in definitiva (e con un'innocente semplificazione) un oggetto che rappresenta un valore che al momento non è noto ma che lo sarà prima o poi nel futuro. Come interagiamo con tale oggetto? Fondamentalmente per mezzo del suo metodo then – che da specifiche ogni promise deve obbligatoriamente implementare– che accetta come parametri le due funzioni che saranno invocate rispettivamente quando la promise viene risolta positivamente o quando viene viceversa rigettata (ad esempio per un timeout).

Molto spesso del corso dei prossimi post ci imbatteremo quindi in codice come il seguente:

Due cose interessanti vanno aggiunte sul funzionamento di questo meccanismo: intanto il metodo then ritorna a sua volta una promise usando il valore di ritorno della nostra funzione per risolvere la stessa o intercettando un'eventuale eccezione lanciata dal nostro codice per rigettarla. Questo vuol dire che possiamo concatenare chiamate al metodo then con una sintassi molto più chiara e interpretabile della "pyramid of doom" caratteristica delle callback. In secondo luogo, essendo oggetti, le promise possono essere sia memorizzate in una variabile che passate da una funzione all'altra, aprendo la porta a scenari molto interessanti che avremo modo di scoprire nei prossimi post:

E TypeScript in tutto ciò?

Aurelia supporta non solo ES5 e ES2015/6 ma anche TypeScript. Ciò vuol dire che possiamo scrivere la nostra applicazione nel modo che preferiamo, anche se il consiglio è ovviamente di evitare ES5 e orientarsi per una delle due opzioni più "moderne".

Nel corso di questa serie userò principalmente ES2015, ma non escludo di fare qualche esperimento anche con TypeScript più avanti. La differenza in realtà non è più così rilevante come era tra ES5 e TypeScript.

Le aggiunte più interessanti di quest'ultimo rispetto a ES2015 sono a mio parere la type safety (cioè la possibilità di definire quale sia il tipo di variabili, parametri e valori di ritorno), i generic (praticamente uguali anche nella sintassi a quelli di C# e molto utili in diverse situazioni) e la possibilità di definire interfacce. Tutte cose utili ma non indispensabili per il proseguo del nostro progetto.

Happy coding!

Aurelia e ASP.NET Core: hello Aurelia!

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Quando ormai il morale della ciurma cominciava a vacillare, ecco finalmente un urlo straziato dalla coffa: Aurelia!!!

Ebbene sì, siamo giunti finalmente al punto in cui siamo pronti ad aggiungere Aurelia al nostro progetto utilizzando ovviamente NPM e JSPM.

Aggiungere NPM

Per prima cosa dobbiamo quindi aggiungere NPM e, con il supporto fornito da Visual Studio, la cosa è estremamente facile. Ci è sufficiente aggiungere un nuovo npm Configuration File al progetto, di tutto il resto si occupa l'ambiente di sviluppo:

Il file – package.json - è di per se stesso abbastanza scarno e possiamo per ora concentrare la nostra attenzione sulla sezione devDependencies dove è possibile specificare le dipendenze da quei pacchetti che sono utili nella fase di sviluppo del progetto, esattamente il caso di JSPM:

Aggiungere JSPM

L'aggiunta di JSPM è infatti ancora più semplice: come abbiamo visto qualche post fa per il nuovo project.json – che contiene le dipendenze NuGet (ma non vi abituate troppo, in Visual Studio 2017 andrà purtroppo in pensione prematura) – anche package.json supporta l'editing manuale con Intellisense, per cui tutto quello che dobbiamo fare è digitare "jspm" all'interno della sezione devDependencies e selezionare la versione che ci interessa referenziare (al momento la 0.16.48). In seguito al salvataggio del file, Visual Studio si occuperà di scaricare il pacchetto e le eventuali relative dipendenze:

Con un po' di pazienza avremo alla fine JSPM elencato tra le dipendenze del progetto. Al momento vi sconsiglio di cliccare sulla freccia accanto al pacchetto JSPM, perché è come aprire il vaso di Pandora (e non fate come Julia Roberts in Nothing Hill… non aprite quella porta):

Aggiungere Aurelia

JSPM deve essere configurato prima di poter essere usato, ma tale inizializzazione può essere fatta congiuntamente con il download del primo pacchetto, ed è esattamente ciò che faremo.

Visual Studio non dispone (ad oggi) di un supporto nativo per JSPM come per NPM o Bower. Come conseguenza, l'installazione dei vari pacchetti dovrebbe essere fatta a riga di comando. In alternativa vi suggerisco di scaricare la comodissima estensione partorita dalla mente sempre viva di Mads Kristensen: si tratta in un Package Installer che consente di installare pacchetti da diverse fonti, wrappando in pratica le chiamate a riga di comando in una maschera semplice ma efficacie:

A seguito dell'installazione dell'estensione avremo disponibile una nuova voce Quick Install Package… nel menu contestuale del progetto (attivabile anche con lo shortcut Shift+Alt+0):

Clicchiamo sulla voce e nella maschera risultante selezioniamo JSPM come fonte, digitiamo "aurelia-framework" come pacchetto e clicchiamo infine su Install:

Come detto alla prima installazione sarà necessario configurare JSPM rispondendo ad una serie di semplici domande:

  • La prima domanda ci chiede se vogliamo registrare le proprietà di JSPM che saranno aggiunte al file package.json di NPM all'interno di un nodo jspm. Confermiamo l'impostazione di default ;
  • La seconda domanda ci chiede di indicare quale sia la web root del nostro progetto. Per quanto abbiamo detto in un precedente post è ovvio che per i progetti ASP.NET Core dobbiamo impostare ./wwwroot;
  • È la volta di configurare la cartella in cui JPSM scaricherà i pacchetti che aggiungeremo al progetto (come ad esempio in questo caso Aurelia). Il default è wwwroot/jspm_packages. Potete scegliere questa cartella secondo le vostre preferenze, io per ora imposterò wwwroot/_libs;
  • È ora il momento della posizione del file config.js che servirà a JSPM per gestire i pacchetti scaricati. Confermiamo il default wwwroot/config.js (e confermiamo anche la sua successiva creazione in automatico);
  • La sesta domanda ci chiede di indicare la URL con cui il nostro sito è esposto pubblicamente. Confermiamo il default /;
  • Siamo alla fine ed è sufficiente confermare il default anche per le ultime due domande: , vogliamo usare un transpiler (cioè un meccanismo per "invecchiare" il codice JavaScript in modo da renderlo compatibile con i browser più anziani) e in particolare vogliamo usare Babel.

Al termine della configurazione il download del pacchetto aurelia-framework (e di tutti i pacchetti da cui esso dipende, Aurelia è strutturato in maniera molto granulare, come ASP.NET Core) inizierà automaticamente:

Al termine del download, nella cartella _libs o in qualunque altra cartella voi abbiate scelto in fase di configurazione, potremo trovare i file JavaScript che compongono il cuore del framework Aurelia (un secondo vaso di Pandora che per ora ignoriamo come il primo).

Se vi accorgete che qualcosa non vi convince nel modo in cui avete impostato JSPM non è mai troppo tardi per tornare indietro. La configurazione è infatti disponibile in parte del file package.json di NPM e in parte nel file config.js di JSPM (che potrebbe ovviamente chiamarsi diversamente che avete scelto di modificare il nome di default).

Prima di poter vedere Aurelia in azione abbiamo bisogno di installare un secondo pacchetto chiamato aurelia-bootstrapper del quale avremo modo di parlare meglio in un prossimo post. Ormai sappiamo come fare: Shift+Alt+0 e via:

Hello Aurelia!

I preliminari sono finiti (il che vuol dire che tempo 5 minuti e saremo giunti alla conclusione): possiamo mettere in piedi la nostra demo. Come tutti i framework SPA, Aurelia ha bisogno di un punto di ingresso, una URL che venga servita da ASP.NET Core come una qualunque risorsa "server" e che contenga al suo interno il codice necessario al framework per mettersi in azione e prendersi carico delle successive richieste sul "client". Per il nostro esempio riutilizzeremo il file index.html, modificando il body per aggiungere il codice necessario ad attivare Aurelia:

Ci sono un po' di cose da notare in questo frammento di codice:

  1. Il primo tag script serve ad importare la libreria SystemJS che si occupa del caricamento asincrono on-demand dei vari moduli che comporranno la nostra applicazione (quelli di Aurelia, di altre librerie che potremmo voler usare come ad esempio Bootstrap e ovviamente quelli che scriveremo noi stessi per implementare la logica applicativa). Come detto in un precedente post, JSPM integra infatti le funzionalità di un package manager con quelle di un module loader per fornire una soluzione completa;
  2. Il secondo tag script serve ad importate il file di configurazione di JSPM che contiene alcune delle impostazioni che abbiamo selezionato in fase di inizializzazione e, soprattutto, l'elenco dei pacchetti aggiunti all'applicazione con il rispettivo albero di dipendenze;
  3. Il terzo tag script utilizza SystemJS per caricare il bootstrapper di Aurelia che si occuperà di caricare e attivare il framework;
  4. L'attributo aurelia-app con cui abbiano decorato il body serve infine ad indicare ad Aurelia in quale parte della pagina vogliamo caricare la nostra SPA.

Abbiamo già accennato nel post precedente che Aurelia è basato su MVVM. Non ci sorprende quindi che una "pagina" di Aurelia è composta da una View (un file HTML) e da un ViewModel (un file JavaScript). Come vedremo nei prossimi post questa coppia di elementi deve rispettare alcune semplici (e soprattutto logiche) regole nelle quali al momento non voglio addentrarmi perché dovremmo altrimenti ulteriormente rimandare il nostro F5 e finirei col perdere una certa scommessa con un certo personaggio.

Al momento limitiamoci a creare un nuovo file JavaScript app.js sotto wwwroot che funga da ViewModel con il seguente contenuto:

Anche la View (il file HTML app.html) sarà decisamente minimale:

In definitiva il nostro progetto dovrebbe alla fine essere strutturato più o meno così:

Siamo pronti! F5 e via:

Indubbiamente il risultato è quello atteso, ma è evidente che qualcosa di magico deve essere successo dietro le quinte perché quello che abbiamo scritto in index.html, app.js e app.html non è assolutamente sufficiente a garantire quello che vediamo. Se apriamo il DOM Explorer ecco come risulta l'HTML ricevuto dal browser:

Un bel po' di cose sono successe e alcune domande richiedono una risposta:

  • Come ha fatto Aurelia a capire che volevamo mostrare il contenuto della pagina app?
  • Che fine ha fatto il tag template che era nel file app.html?
  • Cos'è la strana sintassi che abbiamo usato nel file app.js?

Le risposte a queste domande si possono sintetizzare in tre concetti – convention-over-configuration, HTML5 standard e ES2016 – che saranno l'argomento principale dei prossimi post.

Happy coding!

 

P.S. Il codice sorgente è disponibile su GitHub, basta scaricare la release con lo stesso nome del post (Hello Aurelia! in questo caso).

Aurelia e ASP.NET Core: hello ASP.NET Core!

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Ora che tutte le questioni legate alla maniera di referenziare le dipendenze lato client in un progetto ASP.NET Core sono chiare, possiamo finalmente cominciare a scrivere un po’ di codice nel nostro progetto.

Come tutti i progetti basati su framework SPA, un’applicazione web basata su Aurelia si realizza scrivendo pagine HTML e moduli JavaScript. Seguendo l’approccio MVVM (che è alle fondamenta di Aurelia e di cui parleremo in un prossimo post), le pagine HTML saranno le nostre View (conterranno cioè gli elementi grafici che saranno mostrati all’utente), i moduli JavaScript i nostri ViewModel (conterranno cioè i dati con i quali le viste saranno popolate con le informazioni utili all’utente).

Per ingraziarci i favori degli dei della programmazione, non possiamo che partire dal solito classico esempio: Hello World! Ovviamente nel nostro caso, pur usando ASP.NET Core, sarà un esempio in puro HTML.

Ripartiamo dal progetto creato un paio di post fa, e aggiungiamo il file index.html che, memori di quanto detto nello stesso post, salveremo nella cartella wwwroot e non in quella principale del progetto. Vogliamo infatti che questo file sia servito direttamente al client con una chiamata tipo http://hostname/index.html.

image

Ok, tutto sembra a posto, incrociamo le dita e premiamo F5. Visual Studio compila il progetto e apre il browser puntando alla root dello stesso (http://localhost:18156/). Ci aspetteremmo di vedere il nostro file caricato nel browser ma in realtà quello che otteniamo è la pagina seguente:

image

Potremmo pensare che si tratti di un problema di pagina di default: forse http://localhost:18156/ non viene risolto in http://localhost:18156/index.html per qualche problema di configurazione. Se però scriviamo nella barra degli indirizzi espressamente http://localhost:18156/index.html il risultato non cambia. In ogni caso non si capisce perché il server non ci restituisca un errore 404 (dando quindi l’impressione di trovare il file) ma ci serva poi un contenuto dalla provenienza ignota.

Niente panico, è tutto normale e corretto: nel mondo di ASP.NET Core, out-of-the-box abbiamo poco o nulla. Tutto quello che ci serve va aggiunto e configurato, compreso il fatto che l’applicazione serva i file statici presenti nella cartella wwwroot. ASP.NET Core non ci sta quindi servendo il file index.html (di base non sa come farlo) e questo è il motivo per cui i contenuto è diverso dalle aspettative.

Da dove viene allora il contenuto di cui sopra? Per trovare la soluzione facciamo un piccolo passo indietro e analizziamo un paio di file chiave in un progetto ASP.NET Core, che rappresentano quel poco che abbiamo out-of-the-box nel nostro progetto creato con il layout Empty.

Come prima cosa dobbiamo dire che in ASP.NET Core tutta la parte nascosta alla vista del programmatore che di fatto consentiva alla nostra applicazione di funzionare è – fortunatamente – sparita. Quando nel precedente post abbiamo descritto brevemente le novità di ASP.NET Core, ci siamo soffermati esclusivamente su quanto c’è di nuovo nel nostro progetto vuoto. In realtà chi è abituato a lavorare con ASP.NET avrà senza dubbio notato anche un’assenza abbastanza importante: in ASP.NET Core il file Global.asax è sparito e la parte di configurazione e inizializzazione che eravamo soliti scrivere nei quattro metodi di quella classe si trova ora nei file Program.cs e Startup.cs.

Il primo file, almeno nel nome, ha qualcosa di familiare. Se lo apriamo ci accorgiamo che non ci siamo sbagliati: sembra praticamente identico al file omonimo che viene creato in un’applicazione Console, con tanto di metodo static void Main. Se nelle precedenti versioni di ASP.NET qualcosa di magico consentiva ad un richiesta HTTP indirizzata ad IIS di essere veicolata verso la nostra applicazione, con ASP.NET Core tutto è nelle nostre mani. L’applicazione viene inizialmente lanciata come una “normale” applicazione Console per mezzo del suo classi entry point Main. Ed è proprio all’interno di tale metodo che possiamo definire il modo in cui dovrà funzionare, istanziando e configurando un oggetto di classe WebHostBuilder. Una configurazione di base viene preparata per noi dal template di progetto e per ora non abbiamo necessità di modificarla. Se volete addentrarvi nei dettagli trovate diversi post esplicativi a riguardo. Quello che ci interessa evidenziare è la chiamata UseStartup<T> che istruisce il WebHostBuilder sulla classe che si occuperà della configurazione dell’applicazione. Per default tale classe si chiama Startup:

image

Cioè detto, è chiaro che il successivo posto cui dare un’occhiata è il file Startup.cs che definisce la classe Startup cui fa riferimento il WebHostBuilder come punto di ingresso della nostra applicazione. Questa classe, che come noterete non deriva da alcuna classe base e non implementa alcuna interfaccia, è provvista di due metodi fondamentali: ConfigureServices e Configure.

Sorvolo sulla scelta dei nomi, in ogni caso il primo metodo serve a configurare lo IoC container built-in in ASP.NET Core con tutti i servizi che contiamo di usare nella nostra applicazione, compresi eventualmente quelli di “sistema” come MVC. ASP.NET Core è infatti (finalmente) dotato di un meccanismo di dependency injection intrinseco e integrato nel framework. Visto che in una prima fase non avremo bisogno di utilizzarlo e non voglio divagare inutilmente, per ora ignoreremo cosa sia la dependency injection, cosa sia uno IoC container e come si debba usare il metodo ConfigureServices. Limitiamoci semplicemente ad ignorarlo, lasciamolo desolantemente vuoto come è adesso e andiamo avanti.

Il metodo che più ci interessa è il metodo Configure, che serve a configurare i middleware che comporranno la pipeline di ASP.NET Core. Chi ha avuto modo di arrivare ad ASP.NET Core transitando per OWIN si troverà più a suo agio con questi “strani” termini. Per tutti gli altri cerchiamo di fare un po’ di chiarezza.

Quando il processo che ospita la nostra applicazione riceve una richiesta HTTP, questa viene presa in carico e incanalata come fosse su una catena di montaggio o se scorresse lungo una tubatura petrolifera (detta in inglese pipeline). Nel nostro caso i vari pezzi di questa condotta sono ovviamente componenti software (detti middleware) che, uno dopo l’altro vengono chiamati in causa per esaminare la richiesta e valutare le opportune operazioni necessarie a gestirla. Quando un middleware ritiene di poter fornire una risposta, il processo si arresta e la stessa viene incanalata nel verso opposto, ripassando per tutte le componenti precedentemente visitate, fino a giungere all’utente finale. In caso contrario il middleware è responsabile di passare il controllo al componente successivo:

Questo consente ad ogni middleware di poter agire in diversi modi e momenti:

  • un middleware dedicato all’autorizzazione agirà tipicamente nella fase di ricezione delle richiesta, verificando le credenziali dell’utente e rigettandola nel caso non sia sufficienti o consentendo che questa passi ai componenti successivi in caso contrario;
  • un middleware dedicato al logging agirà molto probabilmente in entrambe le direzioni, prima tracciando le informazioni sulla richiesta in ingresso e poi quelle sulla risposta in uscita;
  • un middleware dedicato a fornire risposte (come ad esempio un framework tipo MVC) agirà infine come “terminale” della “pipeline”, interpretando la richiesta e esaudendola.

image

L’esatto funzionamento di questa architettura esula dai nostri scopi, ma trovate una ricca documentazione in materia, partendo ad esempio dalla documentazione di ASP.NET Core.

Aggiungendo uno o più middleware alla pipeline di ASP.NET Core è quindi possibile configurare l’applicazione affinché si comporti esattamente come desiderato, senza che ulteriori processi non necessari rallentino le operazioni compromettendo le performance.

Aggiungere un middleware è in genere molto semplice. Il metodo Configure prevede infatti un parametro in ingresso di tipo IApplicationBuilder che è fornito di un conveniente metodo UseMiddleware<T> atto appunto all’uopo.

In realtà quasi mai avremo bisogno di ricorrere a tale metodo. Ogni middleware è infatti generalmente fornito di un metodo di estensione che si applica direttamente all’interfaccia IApplicationBuilder, consentendo di scrivere ad esempio direttamente UseRouter invece che UseMiddleware<RouterMiddleware> con il non trascurabile beneficio di poter passare dei parametri opzionali di configurazione “strongly typed”.

Ora che la teoria è un po’ più chiara, torniamo alla pratica ed esaminiamo il metodo Configure. Come si vede il template Empty aggiunge ben poco alla pipeline e la parte che ci interessa maggiormente al momento è l’istruzione app.Run(…) che serve a configurare un particolare middleware che funge sempre da anello terminale della catena e che per tale motivo ha una sintassi leggermente diversa. Il template Empty lo configura usando un anonymous method che, senza prestare attenzione al contenuto della richiesta, si limita a restituire come risposta sempre e comunque il testo “Hello World!”:

image

Ecco dunque da dove arriva il risultato che avevamo ottenuto in precedenza. Ed ecco dove dobbiamo mettere le mani per fare in modo che al posto di questo testo statico ci venga servito il nostro file index.html.

Quello che ci serve è aggiungere alla nostra pipeline un middleware che intercetti la chiamata, si accorga che esiste un file in wwwroot che corrisponde al percorso della richiesta e lo serva al browser direttamente dal file system. Fortunatamente per noi, questioni come questa (ed altre tipiche delle sviluppo di applicazioni web) sono state già risolte e codificate in ASP.NET Core. Si tratta solo di attivare la funzionalità in maniera appropriata perché, come già detto, out-of-the-box la pipeline è completamente vuota per non appesantirla con operazioni superflue che comporterebbero un inutile degrado delle prestazioni.

Posizioniamoci quindi dentro al metodo Configure e modifichiamolo in modo che appaia come segue:

image

In questo modo stiamo chiedendo al framework di intercettare le chiamate ai file statici e servirle direttamente (UseStaticFiles) e di fare in modo che le chiamate alla root sia reindirizzate verso un file di default (UseDefaultFiles). Come si vede dal tratteggio rosso però, il due metodi non vengono riconosciuti dal compilatore e, per quanto ci siamo detti finora, la cosa non ci meraviglia affatto: ASP.NET Core è una federazione di NuGet package e ovviamente il middleware di gestione dei file statici si trova in un package dedicato (sempre al fine di alleggerire il prodotto finale) che per ora non abbiamo referenziato nel progetto.

Cogliamo l’occasione per sfruttare una funzionalità di Visual Studio 2015 che semplifica questo genere di situazioni: come si vede nello screenshot, in corrispondenza della riga di codice che riporta la chiamata a UseStaticFiles, Visual Studio mostra una lampadina accesa; è il segnale che è in grado di suggerirci un modo per risolvere il problema. Se in passato ciò che l’ambiente di sviluppo era in grado di fare era solo proporci l’aggiunta della clausola using al file corrente, oggi è anche in grado di individuare la necessità di aggiungere un nuovo NuGet package e di prendersi carico dell’operazione in totale autonomia:

image

A questo punto siamo pronti a lanciare nuovamente l’applicazione e questa volta il risultato dovrebbe essere quello atteso:

image

Attenzione perché il middleware aggiunto da UseDefaultFiles si limita ad analizzare la richiesta ed eventualmente modificarla: se la URL richiesta è la root del progetto, questa viene sostituita con una URL che fa riferimento al primo dei default file ("default.htm", "default.html", "index.htm", "index.html") rintracciati nella cartella wwwroot. Il middleware non si occupa di servire il file stesso, ragion per cui è sempre necessario aggiungere la chiamata a UseStaticFiles ed è sempre necessario che tale chiamata sia successiva a quella ad UseDefaultFiles per assicurarsi che il middleware che serve effettivamente il file possa lavorare sulla URL già opportunamente modificata. In alternativa è possibile usare il metodo UseFileServer che integra i due precedenti nella giusta sequenza.

Happy coding!

 

P.S. Il codice sorgente è disponibile su GitHub, basta scaricare la release con lo stesso nome del post (Hello ASP.NET Core! in questo caso).

Aurelia e ASP.NET Core: NPM e i suoi fratelli

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Nel precedente post ci siamo lasciati parlando di un nuovo approccio per la gestione delle dipendenze lato client: non più NuGet (che rimane lo strumento ideale per la gestione di quelle lato server e anzi risulta notevolmente potenziato dall’approccio a pacchetti intrinseco nel framework .NET Core stesso) ma NPM. Anzi no, Bower.

Cosa sono NPM e Bower?

Anche se vi sembra di averci capito poco, in realtà la confusione è solo teorica. Non vi preoccupate, avrà modo di diventare pratica nel corso di questo post.

Abbiamo già detto che NPM è l’acronimo di Node Package Manager, cioè l’equivalente NuGet per il mondo Node.js.

Cosa c’è che non va con NuGet? Perché cambiare? Per diversi motivi, meravigliosamente espressi da Gianluca Carucci nella sua sessione dello scorso anno ai Community Days. In breve:

  • mischiare dipendenze lato client e lato server nello stesso strumento contribuisce a creare un’entropia che è crescente all’aumentare delle dimensioni e della complessità del progetto;
  • i pacchetti NuGet delle librerie client-side non sono sempre “ufficiali” e sono comunque il porting degli equivalenti pacchetti Node.js, quindi ha molto più senso andare direttamente alla fonte per ottenere le risorse più aggiornate e consistenti;
  • usando NuGet una serie di fondamentali operazioni – come ad esempio Bundling e Minification, o la trasformazione di file Less in CSS – devono essere svolte con strumenti dedicati di .NET o di Visual Studio che potrebbero non essere disponibili in altri contesti (ricordiamoci sempre che ASP.NET Core è multi-piattaforma).

Ok, abbiamo capito (forse) che affiancare NPM a NuGet può essere una buona idea. Ma perché allora Visual Studio ci suggerisce di usare Bower per installare jQuery? Per capirlo (forse) non dobbiamo dimenticare che Node è un framework per la realizzazione di applicazioni web in JavaScript. In quanto tale, un progetto Node avrà tipicamente bisogno sia delle risorse da utilizzare sul server che di quelle da consumare sul client. Per quanto attiene al codice, tali risorse saranno JavaScript in entrambi i casi, ma per il resto la dicotomia è la stessa che abbiamo appena descritto per i progetti ASP.NET e anche la confusione potrebbe essere la stessa.

E allora se NuGet e NPM sono package manager da utilizzare per gestire le dipendenze lato server (rispettivamente in un progetto ASP.NET e Node), è bene usare qualcosa di specifico – nella fattispecie Bower – per gestire quelle lato client. Bower è un package disponibile su NPM (quindi può essere scaricato e aggiunto al progetto usando NPM) ed è a sua volta un package manager espressamente dedicato alla gestione di risorse lato client – con tutte le loro specificità – che in un progetto web sono tipicamente HTML, CSS, JavaScript. Vista la strada intrapresa da Microsoft per ASP.NET Core, non sorprende che il supporto tanto per NPM quanto per Bower sia decisamente buono in Visual Studio e questo ci semplificherà il compito se non siamo amanti della riga di comando.

A questo punto sembrerebbe tutto chiaro: per procedere nel nostro cammino prima aggiungiamo NPM al nostro progetto ASP.NET Core, quindi lo usiamo per aggiungere Bower, infine usiamo quest’ultimo per installare i package relativi ad Aurelia: il gioco è fatto.

Il terzo incomodo: JSPM

In realtà seguiremo (almeno inizialmente) un percorso leggermente diverso, per rimanere più aderenti all’approccio utilizzato dal team di Aurelia. E qui comincia la parte pratica della confusione.

Il team ho scelto infatti di basare lo sviluppo del framework non su Bower ma su JSPM che altri non è se non “yet another package manager” con qualcosa in più.

Un altro? Sì, un altro! Come mi ha fatto notare Nicolò durante il viaggio verso Future Decoded, usare JavaScript nel 2016 può essere una questione non propriamente immediata da approcciare. Il paradiso dei Geek può rapidamente trasformarsi in un inferno per un “ingenuo” programmatore web che magari proviene da un background ASP.NET. D’altra parte è abbastanza naturale che in un ambiente in cui domina l’open source ogni mattina qualcuno si svegli con in testa “il” nuovo framework che rivoluzionerà (in meglio) il modo di sviluppare software sul pianeta, o anche soltanto con un fork di un framework esistente per meglio adattarlo alle proprie esigenze. I package manager, con la loro pesante influenza sul modo in cui il progetto viene progettato e strutturato, non sfuggono a questa logica.

In definitiva non abbiamo fatto in tempo a scoprire che esiste un package manager specifico per JavaScript, che subito dobbiamo affrontare il fatto che ne esistono in realtà molteplici, ciascuno con caratteristiche leggermente diverse. Tra questi, come detto, il team di Aurelia ha deciso di preferire JSPM.

Visto che non vogliamo deviare troppo dalla nostra rotta, mi limito a dire che JSPM combina le caratteristiche classiche di un package manager (tipo Bower) con l’infrastruttura di caricamento modulare (che permette di caricare i file JavaScript dinamicamente man mano che sono necessari) e con le funzionalità di transpling (che consentono a moduli scritti in ES2015 nativo di essere “convertiti” dietro le quinte in codice JavaScript compatibile con i browser che non lo supportano). In particolare, JSPM usa SystemJS come module loader universale: in questa maniera è possibile caricare moduli di diversi formati (ES2015, AMD, CommonJS, …) da diverse fonti (NPM, GitHub, …). In fase di sviluppo i diversi moduli sono caricati come file separati in modalità asincrona, per il passaggio in produzione è invece possibile ottimizzarli in uno o più bundle con un semplice comando.

La scelta del team non è vincolante: Aurelia è disponibile anche come pacchetto Bower, ed è provvisto anche di un buon supporto per webpack; tuttavia in una prima fase useremo l’approccio consigliato per non mettere troppa carne al fuoco (cosa che nella vita reale mi piace invece fare parecchio).

Happy coding!

Aurelia e ASP.NET Core: lo scheletro del progetto

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Avendo “chiacchierato” abbastanza nel primo post, è ora di mettere le mani su un po’ di codice. Io utilizzerò Visual Studio 2015 Enterprise (Update 3) ma non ho motivo di dubitare che sia possibile fare lo stesso sulla versione Community, su Visual Studio Code o anche utilizzando un qualsiasi editor testuale.

Nel momento in cui scrivo sto utilizzando i Microsoft .NET Core Tools (Preview 2) per Visual Studio.

Apriamo quindi Visual Studio e selezioniamo File > New > Project… e dalla categoria Visual C# > Web selezioniamo il template ASP.NET Core Web Application (.NET Core).

La consueta maschera di creazione del progetto consente di scegliere tra tre diversi template, che al solito aggiungono un po’ di codice di esempio al progetto vuoto. Non ho mai amato troppo queste aggiunte, non tanto perché riempiono il progetto di codice di dubbia utilità, quanto perché proponendo soluzioni preconfezionate fanno perdere di vista il funzionamento di quello che c’è “sotto il cofano”. Scegliamo quindi il template Empty e per ora ignoriamo la sezione relativa ad Azure su cui torneremo magari più avanti:

clip_image001

Dopo aver macinato un po’ l’hard disk, Visual Studio ci propone la struttura di base di una web application basata su ASP.NET Core (in realtà il risultato è leggermente diverso da quello dello screenshot seguente perché io preferisco prima creare una solution vuota, poi aggiungerci il project, spesso facendo anche un po’ di modifiche manuali alla struttura di base delle cartelle che non mi piace). Tanto per non farmi mancare nulla ho deciso di salvare il progetto su un repository Git che si trova sul mio account Visual Studio Team Services (VTST). Al momento non vedo implicazioni tra questo e la nostra “rotta”, quindi andremo avanti facendo finta che si tratti un progetto salvato in locale per poi magari tornare sull’argomento se ci sarà da pubblicare il sito su Azure sfruttando le funzioni di deploy e release management di VSTS:

clip_image002

Ci sono diverse differenze da notare in questa struttura rispetto a quella di un “vecchio” progetto ASP.NET ma non mi dilungherò ad analizzarle tutte in dettaglio visto che ci sono già svariati post su diversi blog che lo fanno egregiamente. Mi limiterò ad evidenziare brevemente quattro aspetti che a parer mio meritano la nostra attenzione.

Tutto è un pacchetto NuGet

Come accennato nel precedente post, ASP.NET Core è distribuito come federazione di pacchetti NuGet. Come conseguenza il nostro progetto non ha più dipendenze dirette con librerie del framework installate sulla nostra macchina, ma solo con quei pacchetti che implementano le funzionalità che ci servono.

Questo è immediatamente evidente aprendo il nodo References e confrontando un progetto basato sul .NET Framework completo con uno basato su .NET Core:

clip_image004

I pacchetti chiave di .NET Core sono i seguenti:

  • System.Runtime: è il nucleo di.NET Core e include ad esempio la definizione dei tipi Object, String, Array, Action e IList<T>;
  • System.Collections: contiene una serie di generic collections di base, come List<T> e Dictionary<K,V>;
  • System.Net.Http: include una serie di classi per le comunicazioni di rete via HTTP, tra cui HttpClient e HttpResponseMessage;
  • System.IO.FileSystem: è un insieme di classi per leggere e scrivere da storage locali o di rete, come File e Directory;
  • System.Linq: include una serie classi per interrogare oggetti, tra cui Enumerable e ILookup<TKey, TElement>;
  • System.Reflection: contiene le note classi per caricare, ispezionare e manipolare i tipi da codice a runtime, come Assembly, TypeInfo e MethodInfo.

È facile capire che il numero di pacchetti da cui un progetto mediamente può dipendere è cresciuto in modo esponenziale rispetto al vecchio approccio. Per fortuna è stata contemporaneamente migliora la gestione dei pacchetti ed è cambiata anche la modalità di visualizzazione sia sotto il nodo References che nella maschera di gestione dei pacchetti.

In un progetto .NET Core ci troveremo generalmente a non referenziare direttamente pacchetti di sistema, ma ad utilizzare invece dei metapackages. Questi ultimi sono pacchetti fittizi che non contengono alcuna funzionalità specifica (praticamente non hanno codice proprio) ma che servono solo per referenziare rapidamente una serie di altri pacchetti definiti come loro dipendenze.

In questo modo da un lato si semplifica l’acquisizione dei diversi pacchetti necessari per un comune progetto, d’altro ci si assicura che le varie versioni dei pacchetti siano tra loro coerenti.

Per il tipo di applicazione che abbiamo in mente, utilizzeremo il Microsoft.NETCore.App metapackage (attualmente alla versione 1.0.0) che include tutte le librerie che fanno parte della distribuzione di .NET Core e definisce inoltre il framework netcoreapp1.0. Approfondire quest’ultimo concetto esula dai miei scopi in questo momento, perché a parer mio non farebbe altro che aggiungere confusione. Se vi interessa potete consultare la documentazione ufficiale.

Come detto, e come si vede qui sopra, anche la modalità di visualizzazione è stata allineata a questo nuovo approccio e per default vengono riportati nella vista solo i pacchetti con dipendenza diretta, dai quali è sempre possibile navigare ad albero per scoprire le eventuali ulteriori dipendenze.

Dulcis in fundo, il nuovo file che contiene la lista dei pacchetti scaricati (il file project.json nella root di progetto) a differenza del precedente è manipolabile direttamente. È possibile digitare nella sezione dependencies il nome di un pacchetto che si vuole aggiungere (con tanto di intellisense) per ottenere lo stesso risultato del menu Manage NuGet Packages… e della Package Manager Console.

b6

Semplice come un file system

In un progetto.NET Core, il Solution Explorer mostra tutti i file presenti nella cartella del progetto: la “vecchia” lista di file inclusi nel progetto elencata nel file .csproj è stata finalmente abbandonata e questo rende molto più facile non solo aggiungere e rimuove file – è sufficiente copiare o cancellare un file nella cartella direttamente dal File Explorer di Windows – ma anche gestire il progetto su repository di codice sorgente quale ad esempio Team Foundation Server (TFS) o la sua controparte su cloud Visual Studio Team Service (VSTS).

clip_image005

Pubblicare solo il necessario

Ad una prima occhiata nel Solution Explorer, la cosa che più di altre salta agli occhi è la presenza di una cartella “particolare” chiamata wwwroot. Ricorda un po’ quella presente in IIS e rappresenta una svolta importante nella gestione delle applicazioni web con ASP.NET.

Fino ad oggi siamo stati abituati al fatto che tutto ciò che era presente nella cartella principale poteva di fatto essere servito al browser dal nostro server web. In un progetto MVC convivevano in maniera promiscua nella root del progetto sia elementi destinati direttamente al client – come ad esempio le immagini contenute nella cartella Images o i file JavaScript contenuti della cartella Scripts – che elementi inerenti il funzionamento lato server dell’applicazione – come i sorgenti presenti nelle cartelle Controllers, Models and Views o ancora il file di configurazione Web.config.

Questi ultimi erano progettati per essere processati all’interno del workflow di MVC ed emettere codice HTML e non per essere serviti direttamente al client (per intenderci con una richiesta HTTP verso la URL http://myapplication/Controllers/HomeController.cs ad esempio). Per evitare che ciò avvenisse, il motore di routing era dotato di una serie di regole che impedivano che certi file fossero raggiungibili direttamente dall’esterno con un meccanismo di blacklist.

In ASP.NET Core questo problema è stato risolto con un approccio radicalmente differente. Tutti, e soli, gli elementi presenti nella cartella wwwroot fanno parte di una whitelist che può essere servita al client direttamente (in altre parole come risorse statiche dotate di specifica URL). Se un file non si trova in wwwroot avete la sicurezza che non sarà possibile raggiungerlo e scaricarlo.

Non tutto è un pacchetto NuGet

L’altra novità rilevante nella lista presentata dal Solution Explorer è il nodo Dependencies che a prima vista sembra un duplicato di quello References di cui abbiamo già parlato, ma in realtà serve a distinguere le dipendenze lato server da quelle lato client, non tanto dal punto di vista logico ma soprattutto da quello dello strumento utilizzato per ottenerle.

Pare infatti che, mentre noi dormivamo beati tra i guanciali di ASP.NET, larga parte del mondo dello sviluppo web procedeva spedito in tutt’altra direzione, appoggiandosi a Node.js per sviluppare in JavaScript anche la parte server delle applicazioni. Anche in questo caso è inutile addentrarsi in un universo enorme e misterioso, sul quale tonnellate di materiale ben più qualificato di quello che potrei scrivere io è già disponibile.

Quello che ci interessa è che attorno a Node è fiorito un ecosistema di librerie e strumenti open source, facilmente accessibili tramite il suo package manager dedicato, NPM. Per chi viene da ASP.NET e sente parlare di NPM per la prima volta, il paragone più immediato è con NuGet. Se fino a ieri eravamo abituati ad usare NuGet per ottenere tanto una libreria .NET da usare nel codice lato server (come ad esempio Json.NET) quanto una JavaScript da usare nelle pagine lato client (vedi jQuery), da oggi Microsoft ha finalmente deciso di essere stanca di reinventare la ruota. NuGet rimane vivo e vegeto per il primo tipo di librerie, mentre per tutto ciò che attiene al client ASP.NET Core e Visual Studio fanno riferimento a NPM, cioè come detto al package manager di Node, in definitiva il più grande contenitore di librerie open source al mondo.

A riprova, se proviamo a cercare jQuery dal Manage NuGet Packages… otteniamo un avvertimento che ci invita ad usare Bower invece che NuGet (ad oggi è solo un avvertimento, non un divieto):

clip_image006

Come Bower? Ma non abbiamo appena detto che saremmo passati da NuGet a NPM? Sì e no; il mondo open source è pieno di sorprese e poi un solo package manager non sarebbe abbastanza nerd.

Ne sapremo di più al prossimo post.

Happy coding!

 

P.S. Il codice sorgente è disponibile su GitHub, basta scaricare la release con lo stesso nome del post (Lo scheletro del progetto in questo caso).

Aurelia e ASP.NET Core: la strana coppia

Questo post fa parte di una serie dedicata ad Aurelia e ASP.NET Core.

Per chi, come me, ha da sempre come pane quotidiano la realizzazione di applicazioni web, in particolare applicazioni con una forte interazione lato client, questi mesi estivi sono stati forieri di entusiasmanti novità.

Nel giro di poche settimane abbiamo infatti assistito al rilascio della RTM di ASP.NET Core (a fine giugno) e di Aurelia (a fine luglio). Mentre sfido chiunque a non aver mai sentito parlare della nuova piattaforma Microsoft per lo sviluppo di applicazione web, molto probabilmente il nuovo framework per realizzare Single Page Application potrebbe essere argomento sconosciuto ai più.

Tanta è l’eccitazione che ho deciso di imbarcarmi in un “viaggio” tra le caratteristiche di questa strana coppia per capire come sfruttarne i rispettivi punti di forza nello sviluppo di un’applicazione web. Premetto subito che non ho alcuna pretesa didattica, non so quale sarà in porto finale di approdo (o lo scoglio di naufragio), non voglio rivelarvi verità clamorose, non so neanche quale rotta seguire e quanto a lungo navigare. In ogni caso, se volete saltare sulla barca, c’è posto.

Prima di levare l’ancora, cerchiamo di capire meglio di cosa (secondo me) stiamo parlando. Come detto, ritengo ASP.NET Core patrimonio di tutti quindi ne farò solo un breve accenno, riservando qualche parola in più ad Aurelia e alla sua storia.

Cos’è ASP.NET Core?

ASP.NET Core è un nuovo framework per realizzare applicazioni web moderne. Rispetto al già noto e strautilizzato ASP.NET, si caratterizza per essere open‑source (sì avete letto bene), cross‑platform (sì avete riletto bene) e fortemente orientato al cloud (e qui non c’è alcuna sorpresa).

ASP.NET Core può girare sia sul .NET Framework “completo” sia sul nuovo .NET Core (da cui in tal caso eredita le caratteristiche di portabilità di cui sopra).

Una particolarità rispetto al passato consiste nel suo design modulare notevolmente granulare. A differenza di come eravamo abituati in ASP.NET “classico” (fa un po’ specie utilizzare questo termine che anni fa abbiamo usato per distinguere il “vecchio” ASP 3 dall’allora innovativo ASP.NET 1.0), con ASP.NET Core possiamo scegliere con estrema flessibilità quali funzionalità includere e quali escludere dalla nostra soluzione, rendendo ovviamente il risultato finale assai più snello e performante.

Se fino a ieri eravamo abituati a partire dal nutrito pacchetto di funzionalità messe a disposizione monoliticamente da ASP.NET, aggiungendoci sopra quelle fornite da librerie di terze parti tramite pacchetti NuGet, oggi le stesse parti di cui il framowork è composto sono distribuite tramite NuGet e possono essere assemblate a piacimento in una specie di federazione di pacchetti.

In tutto ciò, non guastano la nuova modalità di hosting, slegata da IIS, e alcune nuove feature build‑in, come ad esempio un Inversion of Control container per gestire la Dependency Injection.

Cos’è Aurelia?

Aurelia è un framework JavaScript per la realizzazione di UI di nuova generazione.

È l’ultima creazione di Rob Eisenberg, che ci ha già regalato framework come Caliburn.Micro (per lo sviluppo WPF/XAML) e Durandal (per lo sviluppo web).

Un po’ di storia può aiutarci a capire meglio in che contesto ci muoveremo.

Un paio di anni fa, dopo aver ideato Durandal vNext ed aver cercato senza successo di raccogliere fondi su KickStarter per portare avanti il progetto, Rob aveva deciso di abbracciare il lato oscuro, unendosi al team di Angular per contribuire alla realizzazione di Angular 2.

La sua idea era portare la sua competenza ed esperienza nei framework MVVM per realizzare in Angular 2 le idee che aveva ipotizzato per Durandal vNext. Dopo circa dieci mesi di collaborazione le strade di Rob e del team si sono però divise per una differente visione strategica e Rob ha ripreso a lavorare alle idee di Durandal vNext che si sono quindi concretizzate in un nuovo framework: Aurelia.

Come per ogni framework, in rete si trovano decine di definizioni diverse di Aurelia, ognuna con sfumature leggermente diverse, nessuna esatta, nessuna errata. Per me nella sua essenza Aurelia è fondamentalmente un insieme di librerie JavaScript moderne e modulari per realizzare interfacce utente.

Moderne perché sono state scritte dalle fondamenta interamente in ECMAScript 2016 (altrimenti noto come ES7) e supportano quindi nativamente moduli, classi, decoratori e via dicendo, consentendo ovviamente di utilizzare le medesime caratteristiche per scrivere la parte di codice applicativo di nostra competenza.

Modulare perché l’approccio architetturale su cui è basato non è quello che ha caratterizzato tanti giganti monolitici e poco flessibili che abbiamo usato in passato. Aurelia è piuttosto progettato come una rete di librerie che collaborano tra loro per formare un framework potente e solido per sviluppare Single Page Application (SPA). In tal senso i due protagonisti del nostro viaggi si assomigliano parecchio.

Tenendo fede ad un consolidato stile di Rob, anche Aurelia si caratterizza per una notevole facilità d’uso grazie all’approccio convention‑over‑configuration: il framework è dotato di una serie di convenzioni semplici ed immediate che consentono di seguire pattern di programmazione solidi e di ridurre la quantità di codice da scrivere e manutenere. Il che significa potersi focalizzare maggiormente sulla propria applicazione riducendo il tempo speso ad interagire con le API del framework senza perdere però la possibilità di configurare comportamenti diversi ove necessario.

La sua modularità gli consente inoltre di essere facilmente personalizzato ed integrato. Praticamente ogni aspetto di Aurelia è estendibile, il che garantisce di non trovarsi mai di fronte a "scatole chiuse" o di dover "hackerare" il framework per farlo funzionare nel modo desiderato. Ma consente anche di integrare con immediatezza qualsiasi libreria o framework di terze parti, come ad esempio jQuery, React, Polymer o Bootstrap.

Dulcis in fundo, Aurelia è stato progettato attorno alla nuova generazione di JavaScript e ai Web Components, con l'obiettivo di evitare astrazioni superflue che nascondano la tecnologia sottostante, è si propone quindi come il framework che maggiormente rispetta gli attuali standard di programmazione, promettendo di farci scrivere sempre codice JavaScript, senza invasivi costrutti da rispettare.

Direi che siamo pronti per imbarcarci, alla prossima.

Happy coding!

«gennaio»
domlunmarmergiovensab
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234