Estendere ASP.NET MVC


Questo articolo è tratto dal libro ASP.NET 4.5 e ASP.NET MVC 4 in C# e VB - Guida completa per lo sviluppatore di Daniele Bochicchio, Cristian Civera, Marco De Sanctis e Stefano Mostarda.

Acquista subito la tua copia ad un prezzo vantaggioso!

Il processo di una richiesta MVC

L'esecuzione di una richiesta HTTP, soddisfatta attraverso il motore di ASP.NET MVC, segue una pipeline che in gran parte è comune a quelle delle WebForm. Quanto abbiamo visto nel capitolo 5, quindi, è valido anche per ASP.NET MVC, poiché esso si innesca attraverso un handler specifico che dà il via a un'esecuzione diversa dalle WebForm. Sono quindi sempre coinvolti i moduli, prima e dopo l'handler, ma ciò che fa cambiare il modo in cui la richiesta deve essere processata è l'UrlRoutingModule che, grazie alla configurazione delle regole di routing specificate nel global.asax, mappa l'esecuzione su un handler dedicato a MVC. Sebbene quando creiamo un nuovo progetto in Visual Studio 2012 dobbiamo fare una scelta tra WebForm e MVC, possiamo in realtà creare situazioni miste, per poter sfruttare i vantaggi dei due mondi a seconda delle nostre esigenze.

Una volta che abbiamo indirizzato la richiesta al motore MVC, quello che viene chiamato in causa è il controller: il principale componente che gestisce la richiesta. Il controller invoca poi l'action in base al contesto della richiesta e restituisce il risultato. In base a quest'ultimo, può facoltativamente intervenire la parte di view che tramite l'engine processa il model e restituisce l'HTML. Nella figura 15.1 possiamo vedere questo processo e quali sono gli elementi messi in campo per oliare questo meccanismo.

Figura 1

Gli elementi sono molteplici: la ragione è che a ognuno è demandata un'attività. Innanzitutto l'hander MVC delega la creazione del controller a un oggetto che implementa IControllerFactory. L'implementazione predefinita, come sappiamo, cerca una classe in base al parametro controller di route e lo istanzia. Questa operazione è possibile grazie a un altro oggetto che implementa IControllerActivator che ha semplicemente il compito di istanziare una classe di un certo tipo. Normalmente questa operazione è delegata al DepedencyResolver che, come possiamo vedere nella figura 15.1, accompagna tutto il processo e normalmente istanzia direttamente il tipo. Questo resolver però, ci permette eventualmente di sfruttare motori di IoC e iniettare le dipendenze negli oggetti che coinvolgono una richiesta. Una volta creato il controller, la palla passa all'oggetto che implementa IActionInvoker. Anche in questo caso esiste un'implementazione predefinita che fa quanto conosciamo: rintraccia il metodo in base al parametro action di route, costruisce i parametri e il model, attiva i filtri per intervenire prima e dopo l'esecuzione dell'action e, infine, processa l'ActionResult. Potremmo dire, in realtà, che tutto ciò che viene dopo, in termini di model e view, dipende dall'oggetto di invocazione dell'azione, che possiamo personalizzare se, per caso, dovessimo averne bisogno.

Proseguendo sulla strada predefinita, i filtri da applicare per un'action, identificati tramite i FilterAttribute, vengono recuperati tramite istanze del tipo IFilterProvider, le quali cercano nelle impostazioni globali, a livello di classe o sul metodo. Per invocare la funzione, occorre ricostruire il model, perciò vengono chiamate in causa istanze del tipo IModelBinder che, come il nome suggerisce, devono ricostruire il model sulla base della richiesta corrente. L'implementazione predefinita è in grado di costruire tipi primitivi o tipi complessi attraverso la reflection, incrociando i nomi delle proprietà con i parametri della richiesta HTTP. Poiché questi ultimi possono provenire da una form, da file, da JSON o da querystring, arrivano in aiuto molteplici implementazioni di IValueProvider, ognuna per ogni tipologia di fonte. Questo lungo viaggio prosegue poi con la validazione del model, vista nel capitolo precedente, che sfrutta il ModelValidator e le data annotation per compiere questo lavoro. Attraverso il ModelMetadataProvider possiamo personalizzare il modo in cui reperire le informazioni sul model, quali per esempio etichette, descrizioni e modalità di visualizzazione, sfruttate in un secondo momento anche dal motore della view. Anche in questo caso, sappiamo che normalmente vengono usati gli attributi Display, UIHint ecc.

Una volta costruito il model, viene invocata la funzione del controller che restituisce l'ActionResult; se questa è di tipo view, allora l'esecuzione della richiesta passa all'engine Razor o WebForm. Con altre tipologie di risultato, invece, la richiesta termina mandando la risposta all'utente, continuando la pipeline che segue l'handler. La view viene processata attraverso un'istanza del tipo IViewEngine, scelta in base al fatto che sia presente o no un file cshtml/vbhtml o aspx. In entrambi i casi l'engine cerca la view corretta, attraverso le convenzioni sui nomi e i DisplayModeProvider, i quali permettono una scelta sulla base del browser che l'utente sta usando. Successivamente crea le classi temporanee, compila il tipo rappresentativo di ogni view per l'effettivo rendering HTML (come avviene per le WebForm) e lo istanzia attraverso IViewPageActivator. La view, essendo una classe, gode della possibilità di eseguire codice, di usare altre view e di emettere HTML, il tutto sfruttando le caratteristiche del rispettivo parser.

Questa complessa esecuzione chiama in causa parecchi oggetti ma ci fa capire quanto possiamo personalizzare ed estendere il motore che ci ritroviamo. Fatta questa overview, è giunta l'ora di approfondire alcuni di questi concetti, partendo dalle esigenze più comuni.

Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

Estendere ASP.NET MVC 1010 4
| Condividi su: Twitter, Facebook, LinkedIn, Google+

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti