Sei sulla pagina 1di 8

Introduzione ad ASP.NET MVC

Cos’è ASP.NET MVC?

Febbraio 2007. Scott Guthrie Corporate Vice President della Divisione Sviluppo di Microsoft è in volo per partecipare ad una conferenza sulla costa est degli Stati Uniti. Per ingannare l’attesa decide di abbozzare un prototipo destinato a diventare il nucleo fondante di quello che sarà un nuovo framework per lo sviluppo in ambiente web: ASP.NET MVC.

Il progetto prende corpo nei mesi seguenti e a Marzo del 2009 la casa di Redmond rilascia la versione 1,

seguita l’anno successivo dalla 2 e all’inizio di quest’anno dalla versione 3, con la quale il framework raggiunge finalmente una certa maturità e si pone come valida piattaforma di sviluppo web.

Dal punto di vista squisitamente pratico, ASP.NET MVC è un nuovo tipo di progetto disponibile in Visual Studio (2008 o 2010) per realizzare applicazioni web: MVC non sostituisce quindi Web Forms che continuerà ad essere pienamente supportato da Microsoft, come dimostrano anche le novità introdotte con la versione 4 – ma si affianca ad esso, fornendo un’alternativa in più agli sviluppatori .NET. ASP.NET MVC identifica infatti un approccio alternativo al disegno dell’applicazione e rappresenta l’implementazione Microsoft del pattern architetturale MVC, in particolare della sua declinazione nota come Model2. Per tale motivo ASP.NET MVC presenta ovviamente aspetti in comune con altri framework che implementano lo stesso pattern, in particolare con Castle’s MonoRail, senza dubbio uno dei framework MVC più diffusi in ambito .NET.

La presenza di un’alternativa implica come ovvio la necessità di comprendere le differenze tra i due approcci per poter esercitare con cognizione di causa tale possibilità di scelta nell’universo ASP.NET.

Il fatto che la nuova piattaforma si chiami ASP.NET MVC non è infatti una scelta di marketing bensì la chiara indicazione che MVC è parte integrante di ASP.NET. Non per niente il codice di MVC si trova nel namespace System.Web.Mvc cioè dentro System.Web che è poi la casa madre di ASP.NET. Far parte di ASP.NET vuol dire ovviamente poter godere di quelle caratteristiche come la Session, la Membership o la Cache cui siamo già abituati usando Web Forms. Ma vuol dire anche, e questa è una peculiarità di MVC, poter personalizzare il comportamento del sistema, sostituendo una qualunque componente di base con una propria o di terze parti, come nel caso del motore di visualizzazione Razor introdotto nella versione 3 della piattaforma che consente di abbandonare la sintassi dei file .aspx e .ascx per il lato presentation.

I pregi di Web Forms

Visto che MVC non è l’evoluzione di Web Forms ma è un’alternativa a nostra disposizione è naturale chiedersi se era necessaria un’alternativa.

E soprattutto come si può scegliere tra le due alternative quella più adatta al nostro progetto?

Cerchiamo di capirlo partendo proprio da pregi e difetti del framework che abbiamo usato fino ad ora.

La genesi di ASP.NET Web Forms Quando ASP.NET Web Forms venne rilasciato a Gennaio del 2002, il suo obiettivo più o meno dichiarato era quello di avvicinare la vasta platea di sviluppatori VB al mondo web.

Per raggiungere tale obiettivo la piattaforma si proponeva di nascondere dietro una sofisticata astrazione le caratteristiche dei due pilasti della programmazione web: l’HTTP – con la sua natura intrinsecamente stateless – e l’HTML – la cui conoscenza al tempo non era particolarmente diffusa nella massa dei programmatori abituati agli applicativi desktop o client/server.

Si trattava quindi di riproporre lo stesso approccio RAD che aveva fatto il successo di VB: prendo un

controllo, lo rilascio su una form, aggancio del codice ai suoi eventi e il gioco è fatto. L’idea di replicare la stessa esperienza di sviluppo su una piattaforma con caratteristiche così diverse è stato un vero e proprio cavallo di Troia che ha consentito allo stuolo di programmatori VB in difficoltà

nell’approccio con quello che oggi chiamiamo ASP “classico” – di aggredire il mondo delle applicazioni web senza rimanere tagliati fuori dall’esplosione di Internet.

I pilastri di ASP.NET Web Forms Al posto di HTTP e HTML, quello che si presentava (e si presenta tutt’ora) ad uno sviluppatore Web Forms era quindi la classica GUI event-driven traslata in ambiente web attraverso un’articolata gerarchia di potenti controlli lato-server. Controlli in grado di tracciare il proprio stato tra due diverse richieste HTTP (grazie al tanto vituperato ViewState), di renderizzarsi automaticamente in formato HTML e di trasformare i POST lato-client in eventi lato-server. L’approccio alla programmazione web diventava così simile a quello Windows Forms: si trascinavano controlli sulla pagina, si agganciava il codice agli eventi e ci si dimenticava del fatto che il “magico” mantenimento dello stato tra due richieste HTTP indipendenti era garantito dall’astrazione sottostante. Il fatto poi che la parte “visuale” della pagina e quella contenente il codice fossero in due file separati (l’aspx e l’aspx.cs o vb) dava anche l’impressione di aver trovato il santo Graal della separazione tra interfaccia e logica applicativa.

I difetti di Web Forms

Nel corso degli anni e col passare delle versioni ASP.NET Web Forms è stato notevolmente migliorato e raffinato. La filosofia però è rimasta più o meno quella iniziale, anche per i limiti intrinseci dell’architettura, come dimostra anche l’aggiunta dei componenti AJAX.NET, anch’essi progettati per consentire lo sfruttamento della tecnologia AJAX senza addentrarsi nelle specifiche di gestione lato-client e senza quindi la necessità di ricorrere a Javascript o ad XML. In questi anni tuttavia le esigenze della community di sviluppatori si sono evolute, la produttività garantita dallo strumento RAD resta importante ma non tanto da andare a discapito di alcuni aspetti fondamentali della buona programmazione quali la facilità di manutenzione del codice o la chiarezza del disegno architetturale. ASP.NET Web Forms comincia a mostrare i segni del tempo e sono quattro i principali difetti che affiorano nel suo utilizzo.

Illusoria separazione delle responsabilità (Separation of Concern) La separazione delle responsabilità garantita dalla distinzione tra file .aspx e .aspx.cs (o vb) si è rivelata presto illusoria visto che non raggiunge il reale obiettivo di separare il livello di business da quello di presentation che rimangono di fatto fusi nella stessa partial class. Questo non vuol dire che non sia possibile applicare la SoC con ASP.NET Web Forms, quanto piuttosto che la sua applicazione è responsabilità totale dello sviluppatore visto che la piattaforma non lo spinge ad andare in quella direzione ma piuttosto verso quella opposta di limitarsi a creare rapidamente pagine che ottengano in un modo o nell’altro il risultato richiesto.

Controllo limitato sull’HTML prodotto Gli stessi server control che sono stati uno dei motivi del successo di ASP.NET Web Forms sono oggi uno dei punti deboli della piattaforma a causa della limitata possibilità di intervenire sul markup HTML prodotto in fase di renderizzazione. Il controllo sull’HTML si è fatto nel tempo più pressante sia a causa di requisiti non funzionali – quali l’accessibilità del sito, l’uso di CSS, il supporto per browser o dispositivi diversi sia per merito di flessibili librerie lato-client, come jQuery, che hanno semplificato l’approccio con Javascript. D’altra parte pensare di abbandonare i server control equivale a perdere buona parte dei vantaggi della programmazione RAD di ASP.NET Web Forms.

Difficoltà nell’automatizzare le procedure di test Negli ultimi anni ha inoltre assunto un’importanza crescente la fase di test degli applicativi. Quando cerchiamo di testare il nostro software cerchiamo in definitiva di verificare che ad un certo input corrisponda un certo output. Se riusciamo ad automatizzare tale controllo in genere molto tedioso ci

risparmiamo lunghe ore di noia (e soprattutto ci assicuriamo che il controllo venga effettivamente svolto ogni volta). Testare una Web Form vuol dire verificare l’HTTP Response prodotto data una HTTP Request, il che significa non solo riuscire a replicare tutto l’ambiente di runtime in cui il Web Forms gira ma anche verificare l’output in termini di markup HTML sul quale abbiamo visto il controllo è relativo. Testare un’applicazione Web Forms è dunque possibile ma non certo agevole.

Onerosità del ViewState e del ciclo di vita dell’HTTP Request Fin dalla sua introduzione il ViewState è stato uno degli aspetti più criticati dell’intero framework. Anche a causa di un erroneo utilizzo dovuto ad una certa ignoranza sul suo funzionamento, il ViewState può facilmente assumere dimensioni notevoli e questo specie fuori da una intranet può compromettere seriamente prestazioni e funzionalità dell’applicazione, in particolare nell’utilizzo di Ajax che invece per sua natura dovrebbe essere una tecnologia pensata per alleggerire il passaggio di informazioni tra client e server. A questo si aggiunge ovviamente il complesso e oneroso ciclo di vita della richiesta HTTP che deve necessariamente passare per la creazione ex-novo dei vari server control, per l’analisi del ViewState e quindi per il ripristino dello stato della pagina aspx.

Limitare i difetti di Web Forms Ovviamente è possibile limitare alcune di queste problematiche con delle regole di buona programmazione. Ad esempio usando un design pattern come MVP per aumentare la SoC del progetto e quindi la sua testabilità. Le novità di ASP.NET 4 consentono poi di generare un HTML più aderente agli standard. E’ inoltre più comodo disabilitare il ViewState (per mezzo del flag ViewStateMode) usandolo solo per i controlli per cui è necessario, o controllare il client ID generato dai controlli per facilitarne la manipolazione lato-client con Javascript. Restano però delle problematiche strutturali che suggeriscono l’opportunità di pensare un approccio diverso, quello che si realizza con ASP.NET MVC.

Cos’è MVC?

Per capire cosa sia ASP.NET MVC è prima necessario comprendere il funzionamento del design pattern sottostante: MVC. MVC, acronimo di Model-View-Controller, è un pattern architetturale, il cui scopo è quindi di esprimere schemi di base per impostare l'organizzazione strutturale di un sistema software. Anche se il suo approdo nel mondo .NET è abbastanza recente, MVC è il realtà piuttosto datato visto che la sua prima definizione è del 1979 e le prime implementazioni sono in linguaggio Smalltalk. Anche grazie ai comodi strumenti di sviluppo RAD offerti da VB prima e da ASP.NET dopo (o a causa degli stessi, a seconda dei punti di vista), l'applicazione e anche la stessa conoscenza dei design pattern è stata fino ad oggi un po' trascurata dagli sviluppatori su piattaforme Microsoft. MVC è in definitiva una metodologia che ha come scopo principale quello di separare la modellazione delle informazioni, la presentazione delle stesse e la gestione degli input dell’utente in componenti distinte, ciascuna specializzata nel proprio compito. Di ottenere cioè quello che in inglese viene chiamato separation of concerns o SoC. In MVC, il Model rappresenta i dati dell’applicazione e le regole di business utilizzate per manipolarli, la View corrisponde agli elementi della UI e il Controller si occupa di gestire la comunicazione tra l’utente, che opera per mezzo della UI e il modello. È la cosiddetta triade. La definizione originale del pattern era in realtà abbastanza vaga ed MVC è stato declinato in una serie di differenti variazioni nel corso del tempo. Quella alla base di ASP.NET MVC è in particolare molto simile a Model2, una variante ideata da Sun per le sue JSP, che si è rivelata particolarmente adatta alla programmazione in ambito web, affidando al Controller una maggiore responsabilità visto che la modalità di interazione dell’utente con il sistema via HTTP lo rende il naturale punto di ingresso del flusso di operazioni.

Come funziona Model2?

Nella realizzazione di applicazioni web il pattern MVC va infatti opportunamente declinato per tener conto del fatto che ci troviamo a lavorare a cavallo tra due ambienti: il client, dove si trova l’utente tipicamente munito di un browser, e il server dove risiede tutta la logica applicativa.

e il server dove risiede tutta la logica applicativa. Il ciclo comincia quando l’utente effettua una

Il ciclo comincia quando l’utente effettua una HTTP Request verso l’applicazione. Generalmente può trattarsi di una GET (per recuperare informazioni) o di una POST (per modificarle).

In ogni caso tale richiesta viene instradata verso il Controller che la interpreta e determina quali siano le azioni da attivare sul Model, cioè sui dati gestiti dall’applicazione, in genere determinando un cambio di stato del Model stesso.

Il Controller individua quindi la successiva View che deve essere presentata all’utente e passa alla stessa il Model modificato. La View è responsabile di trasformare i dati del Model in un formato adatto alla presentazione all’utente, nel nostro caso di una pagina HTML.

A questo punto la Response viene inviata sul client dove il browser la visualizza all’utente.

Il panorama MVC sul web

ASP.NET MVC non è certo il primo framework per creare applicazioni web basate su MVC. Da questo punto di vista Ruby on Rails è senza dubbio il più popolare. Nato nel 2004 si sviluppa su due fondamentali linee guida: Convention over Configuration (CoC) – cioè l’idea di dare per assodate alcune tecniche dimostratesi funzionali nello sviluppo web utilizzandole come comportamento di base in mancanza di una specifica diversa configurazione – e Don’t Repeat Yourself (DRY) – cioè l’idea di centralizzare la logica applicativa evitando di ripetere lo stesso codice in più punti e mantenendo così il codice più pulito. Linee guida che caratterizzano anche gli altri framework e lo stesso ASP.NET MVC. Come ad esempio Django, basato sul linguaggio Python, che si caratterizza in particolare per le regole di Routing esprimibili per mezzo di espressioni regolari. Nel mondo Java ci sono diversi framework MVC ma i più noti direi che sono Spring, Struts e JSF. Pur con delle differenze, tutti e tre implementano il pattern MVC con particolare attenzione alla separazione delle responsabilità. Anche su PHP, in genere considerato linguaggio che favorisce una codifica non proprio rigorosa, è disponibile un framework MVC chiamato Zend. Prima della nascita di ASP.NET MVC l’opzione più valida in ambito .NET era senz’altro rappresentata da MonoRail, un framework facente parte del progetto Castle, caratterizzato da una grande flessibilità e facilità di interazione con componenti di terze parti, quali NHibernate per il Model o log4net per il log.

Ciclo di vita di una richiesta in ASP.NET

Abbiamo appurato che ASP.NET MVC è un’alternativa a Web Forms nella creazione di applicazioni web. Dato che la maggior parte di chi approccia MVC viene da una precedente esperienza Web Forms cerchiamo subito di capire in che modo i due framework si differenziano nell’interazione con l’utente, cioè in definitiva nella gestione delle richieste HTTP.

ci oè in definitiva nella gestione delle richieste HTTP. Più o meno tutti conosciamo il ciclo

Più o meno tutti conosciamo il ciclo di vita di una Web Form che è poi il ciclo di vita di una richiesta HTTP. Ogni richiesta proveniente da un client viene gestita in ASP.NET da un componente dedicato detto HTTP handler, la cui scelta dipende da un algoritmo interno del runtime di ASP.NET. Nel Web Forms tale algoritmo si basa strettamente sulla URL della pagina richiesta, per cui ogni pagina ha un suo HTTP handler che corrisponde più o meno alla pagina .aspx stessa. In pratica un HTTP handler è una classe .NET che implementa l’interfaccia IHttpHandler il cui unico metodo ProcessRequest è responsabile di interpretare la request e produrre un’adeguata response . La System.UI.Page di Web Forms è un’implementazione di IHttpHandler molto sofisticata che, nel corso dell’esecuzione del metodo ProcessRequest, lancia gli eventi Page_Load, Page_PreRender ma anche Button_Click, cui siamo abituati a rispondere per scrivere il nostro codice. In MVC la scelta dell’HTTP handler che debba gestire una particolare richiesta non è semplicemente basata sul nome del file richiesto ma è affidata ad un modulo ad hoc detto URL routing che si occupa di analizzare la URL della richiesta e determinare quale HTTP handler deve gestirla tra tutti quelli registrati. In MVC in realtà tutte le richieste vengono inoltrate ad un unico handler, la classe MvcHandler che funge da punto centrale per l’attivazione del Controller – scelto sulla base dei parametri che compongono la URL che sarà responsabile della gestione della richiesta. Il Controller, nel rispetto del principio SoC ispiratore di MVC, si appoggia a sua volta su una View per la produzione del markup HTML da restituire al client.

Ciclo di vita di una richiesta con ASP.NET MVC

Scendendo ad un livello di dettaglio maggiore possiamo vedere come la caratteristica SoC di MVC si esplicita in un variegato insieme di componenti diverse, ognuna responsabile di una ristretta e ben specifica parte del processo.

Abbiamo già detto che quando giunge una nuova richiesta HTTP, questa viene presa in carico

Abbiamo già detto che quando giunge una nuova richiesta HTTP, questa viene presa in carico dal modulo di URL routing. Il modulo confronta la URL associata alla richiesta con l’insieme delle Route registrate sull’applicazione e determina quale sia il Ruote handler che deve prenderla in carico. Questo ha il solo compito di determinare il corrispondente HTTP handler (che di base è sempre la classe MvcHandler) che a sua volta esamina il dettaglio della richiesta per individuare il Controller a cui farla gestire. Il Controller non viene istanziato direttamente ma per mezzo di una classe di servizio ControllerFactory. È compito quindi del Controller, per mezzo di un opportuno componente detto ActionInvoker, determinare quale sia l’Action (cioè in definitiva il metodo) cui far svolgere le operazioni connesse alla richiesta. Nel passare il controllo all’azione il Controller chiede aiuto al Model binder per associare automaticamente i parametri richiesti dal metodo alle informazioni fornite dalla Request. In questa fase entrano in azione anche gli Action filter che consentono di aggiungere in maniera dichiarativa comportamenti aggiuntivi all’azione, ad esempio richiedendo una particolare autenticazione, o limitandone l’attivazione al metodo GET o POST o ancora impostando il salvataggio in cache dei risultati dell’azione. Dopo aver svolto le sue operazioni, coinvolgendo il livello di business logic e quindi il Model, l’Action non si occupa direttamente di produrre interfaccia utente ma restituisce invece un Action result che viene analizzato dal Controller per decidere quale View debba essere investita della responsabilità di costruire la Response per l’utente. Questa operazione viene svolta per mezzo di un view engine che è in grado di interpretare il template rappresentato dalla View, integrarlo con i dati provenienti dal Model e produrre il definitivo risultato.

Ad un primo approccio uno schema così dettagliato può far pensare ad ASP.NET MVC come un framework tremendamente complesso e difficile dunque da gestire ed utilizzare. In realtà non dobbiamo leggere la numerosità di componenti come un problema bensì come un’opportunità: l’opportunità di intervenire in molteplici punti del ciclo di vita per personalizzare il funzionamento della nostra applicazione ad un livello sconosciuto in Web Forms. Sempre ricordando che si tratta di un opportunità e non di un obbligo: per ognuno dei componenti descritti esiste infatti un’implementazione standard, già fornita con il framework, in grado di coprire la maggior parte della situazioni normali senza alcuna necessità di personalizzarne il comportamento.

I pilastri di ASP.NET MVC

Stante il quadro generale tracciato fino ad ora, dovrebbero essere chiari a tutti i punti di forza di ASP.NET MVC. In primo luogo una separazione delle responsabilità intrinseca nel framework. Ho già avuto modo di dire che è possibile ottenere una SoC anche con Web Forms impegnandosi ad usare regole di buona programmazione, magari con ausilio di pattern quali MVP. Ma si tratta appunto dell’impegno del programmatore che sotto lo stress di una scadenza imminente o di un budget ristretto può facilmente

vacillare. In MVC la distinzione tra Model, Controller e View induce a rispettare la SoC in maniera più naturale, più guidata (o se preferite forzata) da parte della stessa infrastruttura. SoC in MVC vuol dire quindi tanti piccoli componenti (come abbiamo visto studiando il ciclo di vita della request), ognuno con il suo ruolo preciso e definito, piuttosto che la monolitica classe Page.

Altro pilastro fondamentale è la facilità di testare il codice. Tutti i componenti sono infatti basati su

interfacce e sono quindi facilmente mockabili, cioè sostituibili nel corso del test con componenti fittizi che restituiscono un risultato prefissato. In questo modo è possibile condurre uno unit test su un particolare metodo senza preoccuparsi delle condizioni esterne allo stesso.

Il pieno supporto alla Dependency Injection consente di effettuare tale sostituzione in maniera semplice e immediata.

A differenza di Web Forms, MVC non richiede che l’applicazione giri nel processo ASP.NET per essere

testata, grazie all’astrazione del contesto della richiesta HTTP (le classi HttpContext, HttpRequest, ecc.) che vengono incapsulate in classi astratte sganciate dalla pipeline di ASP.NET. Pur essendo integrato in Visual Studio a partire dalla versione Professional (ed essendo quindi per molti la

scelta più naturale), MVC non richiede necessariamente MSTest ma è invece compatibile con ogni framework di test in ambiente .NET (NUnit, ecc.).

Un altro aspetto che merita di essere considerato, specie da chi in passato ha avuto modo di scontrarsi con una certa rigidità del Web Forms, è la capacità di estensione del framework: come ho già detto tutti i componenti core sono liberamente sostituibili o estendibili con il massimo della flessibilità. Flessibilità che vuol dire poter estendere ma non doverlo fare. L’implementazione di base fornita con MVC è infatti in grado di coprire gran parte delle esigenze e l’utilizzo della Convention over configuration consente di non dover “reinventare ogni volta la ruota” potendosi appoggiare su approcci ritenuti convenzionalmente ottimali salvo poter sempre configurare un comportamento diverso e più adatto alla nostra specifica esigenza.

Questi aspetti sono senza dubbio quelli più qualificanti. Potremmo poi accennare al potente motore di routing che consente di utilizzare URL compatibili con SEO e con REST, o all’estremo controllo del markup HTML prodotto che permette di rispettare più facilmente requisiti non funzionali sull’accessibilità dell’applicazione o sul supporto multi-browser.

WebForms fa per te se…

Ora che abbiamo più chiaro l’approccio di entrambi i framework, torniamo a chiederci quando optare per uno o per l’altro. Potremmo continuare a scegliere Web Forms se preferiamo una piattaforma matura e con un ottimo supporto di componenti di terze parti che ci consenta di “muoverci sul sicuro”. Sicuramente dobbiamo sceglierla se le competenze HTML e Javascript del nostro gruppo di lavoro sono limitate. Grazie ai server control possiamo infatti continuare a limitare il nostro utilizzo di codice lato-client cosa impossibile in MVC. Stessa valutazione nel caso di un’applicazione esistente per la quale sia fondamentale preservare gli investimenti fatti.

O ancora nel caso di applicazioni abbastanza semplici da realizzare in tempi rapidi con pochi sviluppi futuri.

In questo caso l’aspetto RAD di Web Forms potrebbe aiutarci mentre l’impianto SoC di MVC non avrebbe modo di esprimere le sue migliori qualità nel lungo periodo.

MVC fa per te se…

In quali casi la nostra scelta potrebbe cadere invece su ASP.NET MVC? Beh sicuramente se il Test Driven Design e lo Unit Testing sono una nostra priorità vista che l’archiettura del framework si sposa perfettamente con queste esigenze. Ma anche se cerchiamo un framework fortemente SoC-oriented che ci aiuti a realizzare un’applicazione facilmente mantenibile e scalabile.

O ad esempio se vogliamo il completo controllo del markup della pagina HTML

Magari perché facciamo un notevole utilizzo di librerie Javascript. O perché usiamo molto Ajax e vogliamo

farlo in libertà e semplicità, senza l’infrastruttura del ViewState e dell’oneroso ciclo di vita della Web Form.

O ancora perché abbiamo bisogno di personalizzare il comportamento delle componenti core del

framework, potendo agire in un qualunque punto della gestione della richiesta.

In conclusione

ASP.NET MVC è un nuovo approccio alla programmazione web, è parte integrante di ASP.NET, sviluppato dallo stesso team che lavora su Web Forms a cui si aggiunge come alternativa e non come sostituto.

Si sposa perfettamente con TDD anche grazie ad una nativa separazione delle responsabilità e ad una

componentistica modulabile ed estensibile facilmente.

Rispetto a Web Forms richiede qualche conoscenza in più del mondo web e dei design pattern, una maggiore consapevolezza di quello che si fa, e questo lo rende un framework alla portata di molti ma non di tutti.