3. Controller, azioni, routing
Consideriamo l'architettura di un'applicazione ASP.NET MVC:
![]() |
In questo capitolo, esaminiamo il processo che instrada la richiesta [1] al controller e all'azione [2a] che la elaborerà, un meccanismo noto come routing. Presentiamo inoltre le varie risposte [3] che un'azione può restituire al browser. Queste possono essere diverse da una vista V [4b].
3.1. La struttura di un progetto ASP.NET MVC
Creiamo il nostro primo progetto ASP.NET MVC utilizzando Visual Studio Express 2012. Lo aggiungeremo [1] alla soluzione utilizzata nel capitolo precedente:
![]() |
![]() |
- in [2], il nome del nuovo progetto;
- in [3, 4], scegliamo un progetto ASP.NET MVC di base. Questo modello ci fornisce un'applicazione web vuota che include comunque tutte le risorse (DLL, librerie JavaScript, ecc.) necessarie per iniziare.
Il progetto risultante è mostrato in [5]. Lo imposteremo [6] come progetto iniziale della soluzione ( ):
![]() |
Si notino i seguenti punti in [5]:
- l'architettura del progetto riflette il suo modello MVC:
- i controller C saranno collocati nella cartella [Controllers],
- i modelli di dati M saranno collocati nella cartella [Models],
- le viste V saranno collocate nella cartella [Views],
![]() |
- in [1], il file [Site.css] sarà il file CSS predefinito dell'applicazione;
- in [2] sono disponibili diverse librerie JavaScript;
- in [3], ci sono tre viste specifiche: _ViewStart, _Layout ed Error.
Il file [_ViewStart] è il seguente:
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
- Riga 1: Il carattere @ indica l'inizio di un blocco C# all'interno della vista. Infatti, il codice C# può essere incluso in una vista;
- riga 2: definisce una variabile Layout che specifica la vista padre per tutte le viste. Corrisponde alla pagina master nel framework ASP.NET classico.
Il file [ _Layout ] è il seguente:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
@RenderBody()
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
</body>
</html>
Quando viene visualizzata una vista dalla cartella [Views], il suo corpo verrà visualizzato dalla riga 11 sopra. Ciò significa che la vista non deve includere i tag <html>, <head> e <body>. Questi sono forniti dal file sopra. Per ora, questo file è piuttosto criptico. Semplifichiamolo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Tutoriel ASP.NET MVC</title>
</head>
<body>
<h2>Tutoriel ASP.NET MVC</h2>
@RenderBody()
</body>
</html>
- riga 6: il titolo comune a tutte le viste;
- riga 9: l'intestazione comune a tutte le viste;
- riga 10: il contenuto specifico della vista visualizzata.

- [Web.config] è il file di configurazione dell'applicazione web. È complesso. Dovrai modificarlo quando utilizzi il framework [Spring.net] in un'architettura multilivello.
- [Global.asax] contiene il codice eseguito all'avvio dell'applicazione. Generalmente, questo codice utilizza i vari file di configurazione dell'applicazione, incluso [Web.config].
3.2. Indirizzamento URL predefinito
Il codice in [Global.asax] è attualmente il seguente:
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace Exemple_01
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
}
}
}
- Riga 6: lo spazio dei nomi della classe. Deriva direttamente dal nome del progetto ed è elencato nelle proprietà del progetto:

![]() |
Impostiamo [1] come spazio dei nomi predefinito. Verrà quindi utilizzato per impostazione predefinita per tutte le classi che verranno create nel progetto.
Torniamo al codice in [Global.asax]:
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace Exemple_01
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
}
}
}
- riga 9: la classe [MvcApplication] deriva dalla classe [HttpApplication]. Il nome [MvcApplication] può essere modificato;
- riga 11: il metodo [Application_Start] è il metodo eseguito all'avvio dell'applicazione web. Viene eseguito una sola volta. È qui che l'applicazione viene inizializzata.
Il codice per [Application_Start] è attualmente il seguente:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Per ora non è necessario comprendere tutto questo codice. Le righe 5–8 definiscono i percorsi accettati dall'applicazione web. Torniamo all'architettura di un'applicazione ASP.NET MVC:
![]() |
Abbiamo spiegato che il [Front Controller] deve instradare un URL all'azione responsabile della sua gestione. Un percorso viene utilizzato per collegare un modello di URL a un'azione. Questi percorsi sono definiti nella cartella [App_Start] del progetto dalle classi [WebApiConfig, FilterConfig, RouteConfig, BundleConfig]:

Per ora, ci interessa solo la classe [RouteConfig]:
using System.Web.Mvc;
using System.Web.Routing;
namespace Exemple_01
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
Le righe 12–16 definiscono il formato degli URL accettati dall'applicazione. Questo è chiamato percorso. Possono esserci più percorsi possibili (= più modelli di URL possibili). Si distinguono l'uno dall'altro per il loro nome (riga 13). Il formato degli URL del percorso è definito alla riga 14. Qui, l'URL avrà tre componenti:
- {controller}: il nome di una classe derivata da [Controller]. Verrà cercata nella cartella [Controllers] del progetto. Per convenzione, se l'URL è /X/Y/Z, il controller responsabile della gestione di questo URL sarà la classe XController. Il suffisso Controller viene aggiunto al nome del controller presente nell'URL;
- {action}: il nome di un metodo nel controller specificato sopra. Questo metodo riceverà i parametri che accompagnano l'URL e li elaborerà. Questo metodo può restituire vari risultati:
- void: l'azione costruirà la risposta al browser del cliente
- String: l'azione restituisce una stringa al client;
- ViewResult: restituisce una vista al client;
- PartialViewResult: restituisce una vista parziale;
- EmptyResult: al client viene inviata una risposta vuota;
- RedirectResult: indica al client di reindirizzarsi a un URL
- RedirectToRouteResult: come sopra, ma l'URL viene costruito a partire dai percorsi dell'applicazione;
- JsonResult: invia una risposta JSON
- JavaScriptResult: restituisce codice JavaScript al client;
- ContentResult: restituisce un flusso HTML al client senza passare attraverso una vista;
- FileContentResult: restituisce un file al client;
- FileStreamResult: come sopra, ma tramite un metodo diverso;
- FilePathResult: ...
- {id}: un parametro che verrà passato all'azione. Affinché funzioni, l'azione deve avere un parametro denominato id.
La riga 15 definisce i valori predefiniti quando l'URL non ha il formato previsto /{controller}/{action}/{id}. Indica inoltre che il parametro {id} nell'URL è facoltativo. Ecco un elenco di URL incompleti e l'URL completato con i valori predefiniti:
URL originale | URL completato |
/ | /Home/Index |
/Fare | /Fare/Indice |
/Fare/Qualcosa | /Fare/Qualcosa |
/Fare/Qualcosa/4 | /Fare/Qualcosa/4 |
/Fai/Qualcosa/x/y/z | URL non instradato |
3.3. Creazione di un controller e di una prima azione
Creiamo un primo controller:

![]() |
- In [1], inserisci il nome del controller con il suffisso [Controller];
- in [2], creare un controller MVC vuoto;
- in [3], è stato creato.
Il codice per [FirstController] è il seguente:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Exemple_01.Controllers
{
public class FirstController : Controller
{
//
// GET: /First/
public ActionResult Index()
{
return View();
}
}
}
- riga 7: è stato generato uno spazio dei nomi predefinito;
- riga 9: la classe [FirstController] deriva dalla classe [System.Web.Mvc.Controller];
- righe 14–17: è stata generata un'azione [Index] per impostazione predefinita. È pubblica. Questo è importante; altrimenti, non verrà trovata. Restituisce un tipo [ActionResult], che è una classe astratta da cui derivano la maggior parte dei risultati tipicamente restituiti da un'azione. Si tratta di un tipo "catch-all" che può essere specificato sostituendolo con il nome effettivo del tipo restituito;
- Riga 16: il metodo non fa nulla. Restituisce semplicemente una vista, ovvero un tipo [ViewResult]. Il nome della vista non è specificato. In questo caso, il framework cerca nella cartella [Views/First] una vista con lo stesso nome dell'azione, che in questo caso è [Index.cshtml].
Creiamo la vista [Index.cshtml]:
![]() |
- in [1], fare clic con il pulsante destro del mouse sul codice dell'azione e selezionare l'opzione [Aggiungi vista];
- in [2], la procedura guidata suggerisce una vista con lo stesso nome dell'azione. È proprio quello che vogliamo in questo caso;
- in [3], per impostazione predefinita, viene suggerito l'uso della pagina master [_Layout.cshtml];
- in [4], una volta confermata, la procedura guidata crea la vista in una sottocartella della cartella [Views] che prende il nome dal controller (First).
Il codice generato per la vista [Index] è il seguente:
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
- Righe 1–3: codice C# che definisce una variabile;
- riga 5: un tag HTML.
Sostituisci tutto il codice precedente con questo:
<strong>Vue [Index]...</strong>
Riassumendo:
- abbiamo un controller C# chiamato [First];
- abbiamo un'azione chiamata [Index] che richiede la visualizzazione di una vista chiamata [Index];
- abbiamo la vista V [Index].
Possiamo chiamare l'azione [Index] in due modi:
- /First/Index;
- /First, poiché [Index] è anche l'azione predefinita nelle rotte.
Eseguiamo l'applicazione (CTRL-F5). Otteniamo la seguente pagina:

In [1], l'URL richiesto era http://localhost:49302. Manca il percorso. Sappiamo che il nostro router si aspetta URL nella forma /{controller}/{action}/{id}. Poiché questi elementi mancano, vengono utilizzati i valori predefiniti. L'URL diventa http://localhost:49302/Home/Index. Il controller [Home] non esiste. Pertanto, l'URL viene rifiutato.
Ora proviamo l'URL http://localhost:49302/First/Index digitandolo direttamente nel browser:
![]() |
La pagina sopra è stata generata dall'azione [Index] del controller [First]. La pagina generata da questa azione è la vista [Index], il cui codice era il seguente:
<strong>Vue [Index]...</strong>
Genera la parte [1]. La parte [2], invece, proviene dalla pagina master [_Layout] che abbiamo definito in precedenza:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Tutoriel ASP.NET MVC</title>
</head>
<body>
<h2>Tutoriel ASP.NET MVC</h2>
@RenderBody()
</body>
</html>
La riga 9 ha generato la sezione [2] della pagina. La vista [Index], tuttavia, appare solo alla riga 10.
Se visualizziamo il codice sorgente della pagina ricevuta, possiamo vedere che la pagina [Index] è effettivamente inclusa (riga 10 qui sotto) nella pagina [Layout]:
Ora proviamo l'URL [/First]:

L'URL [/First] era incompleto. È stato completato con i valori predefiniti del percorso ed è diventato [/First/Index]. Otteniamo quindi lo stesso risultato di prima.
3.4. Azione con un risultato di tipo [ContentResult] - 1
Creiamo una nuova azione nel controller [First]:
using System.Text;
using System.Web.Mvc;
namespace Exemple_01.Controllers
{
public class FirstController : Controller
{
// Index
public ViewResult Index()
{
return View();
}
// Action01
public ContentResult Action01()
{
return Content("<h1>Action [Action01]</h1>", "text/plain", Encoding.UTF8);
}
}
}
La nuova azione è definita nelle righe 14–18. Restituisce semplicemente una stringa utilizzando il metodo [Content] (riga 16) della classe [Controller] (riga 6). I parametri del metodo sono:
- la stringa di risposta;
- un indicatore del tipo di testo inviato: "text/plain", "text/html", "text/xml", ecc. Questo indicatore è chiamato tipo MIME (http://fr.wikipedia.org/wiki/Type_MIME);
- il terzo parametro specifica il tipo di codifica utilizzato per il testo.
Anziché utilizzare il tipo astratto [ActionResult], i nostri metodi specificano il tipo di ritorno effettivo (righe 9 e 14).
Richiediamo l'URL [/First/Action01]. Otteniamo la seguente pagina:

Diamo un'occhiata al codice sorgente della pagina ricevuta:
Il browser ha ricevuto solo il testo inviato dall'azione e nient'altro. Questa modalità è utile quando si desidera richiedere dati grezzi dal server web senza il markup HTML circostante. Si noti che il browser non ha interpretato il tag HTML <h1>. Per capire perché, diamo un'occhiata agli scambi HTTP in Chrome:
Il browser ha inviato le seguenti intestazioni HTTP:
Il server ha risposto con le seguenti intestazioni:
- Riga 3: imposta il tipo di documento. Vediamo gli attributi impostati nel metodo [Action01]. È perché al browser è stato comunicato che il documento era di tipo "text/plain" e non "text/html" che non ha interpretato il tag <h1> presente nel documento ricevuto.
3.5. Azione con un risultato di tipo [ContentResult] - 2
Consideriamo la seguente terza azione:
using System.Text;
using System.Web.Mvc;
namespace Exemple_01.Controllers
{
public class FirstController : Controller
{
...
// Action02
public ContentResult Action02()
{
string data = "<action><name>Action02</name><description>renvoie un texte XML</description></action>";
return Content(data, "text/xml", Encoding.UTF8);
}
}
}
- riga 12: definiamo un testo XML;
- riga 13: lo inviamo al browser, specificando che si tratta di XML con il tipo MIME "text/xml".
Nel browser, otteniamo la seguente pagina:

Diamo un'occhiata alla risposta HTTP del server in Chrome:
- Riga 3: specifica il tipo di documento. Qui sono inclusi gli attributi impostati nel metodo [Action02];
- Riga 12: La dimensione in byte del documento inviato dal server.
Il documento inviato dal server è questo (screenshot di Chrome):

3.6. Azione con un risultato di tipo [JsonResult]
Aggiungiamo la seguente azione al controller [First]:
// Action03
public JsonResult Action03()
{
dynamic personne = new ExpandoObject();
personne.nom = "someone";
personne.age = 20;
return Json(personne,JsonRequestBehavior.AllowGet);
}
- riga 4: una variabile di tipo dynamic. In fase di esecuzione, è possibile aggiungere liberamente proprietà a tale variabile. La proprietà viene creata nel momento stesso in cui viene inizializzata;
- righe 5-6: inizializziamo due proprietà, nome ed età;
- riga 7: restituisce la rappresentazione JSON (JavaScript Object Notation) dell'oggetto. JSON consente di serializzare un oggetto in una stringa e, viceversa, di deserializzare una stringa in un oggetto. È un'alternativa alla serializzazione/deserializzazione XML;
- riga 2: l'azione restituisce un tipo [JsonResult]. Questo tipo può essere restituito solo per una richiesta POST. Se si desidera restituirlo per un metodo GET, è necessario impostare il secondo parametro del costruttore della classe Json (riga 7) su JsonRequestBehavior.AllowGet.
Quando si richiede l'URL [/First/Action03], il browser visualizza quanto segue:

La risposta HTTP del server è la seguente:
- Riga 3: specifica che il documento inviato è in formato JSON;
- riga 10: il documento inviato è di 58 byte. È il seguente:
L'elemento dinamico [person] viene interpretato da JSON come un array di dizionari in cui ogni dizionario:
- corrisponde a un campo della variabile [person];
- ha due chiavi, "Key" e "Value". "Key" ha come valore associato il nome del campo, mentre "Value" ha il valore del campo.
3.7. Azione con un risultato [string]
Aggiungiamo la seguente azione al controller [First]:
// Action04
public string Action04()
{
return "<h3>Contrôleur=First, Action=Action04</h3>";
}
Quando richiediamo l'URL [/First/Action04] in Chrome, otteniamo la seguente risposta:

Possiamo notare che il tag <h3> è stato interpretato. Diamo un'occhiata alla risposta HTTP del server:
e il seguente documento:
Come si vede alla riga 3, il server ha indicato che stava inviando testo in formato HTML. Questo è il motivo per cui il browser ha interpretato il tag <h3>. Quando si desidera inviare testo semplice, è quindi preferibile restituire un [ContentResult] piuttosto che una [string]. Il [ContentResult] ci permette di specificare un tipo MIME "text/plain" per indicare che stiamo inviando testo non formattato, che il browser non tenterà di interpretare.
3.8. Azione con un tipo [EmptyResult]
Consideriamo la seguente nuova azione:
// Action05
public EmptyResult Action05()
{
return new EmptyResult();
}
L'azione restituisce semplicemente un tipo [EmptyResult]. In questo caso, il server invia una risposta vuota al client, come mostrato nella sua risposta HTTP:
- Riga 9: Il server informa il proprio client che sta inviando un documento vuoto.
3.9. Azione con un risultato di tipo [RedirectResult] - 1
Si consideri la seguente nuova azione:
// Action06
public RedirectResult Action06()
{
return new RedirectResult("/First/Action05");
}
L'azione restituisce un tipo [RedirectResult]. Questo tipo consente di inviare al client una richiesta di reindirizzamento all'URL specificato nel costruttore (riga 4). Il client invierà quindi una nuova richiesta GET a [/First/Action05]. Il client effettua quindi due richieste in totale.
Il browser visualizza il risultato della seconda richiesta:

Esaminiamo la risposta HTTP del server in Chrome:

Sopra vediamo le due richieste del browser. Esaminiamo la prima richiesta [Action06]. La risposta HTTP del server è la seguente:
- Riga 1: Il server ha risposto con un codice di stato 302 Found. In precedenza era 200 OK, il che significa che il documento richiesto è stato trovato. Il codice 302 indica che è richiesto un reindirizzamento. L'URL di reindirizzamento è fornito alla riga 4. Questo corrisponde all'URL di reindirizzamento che abbiamo specificato nel codice dell'azione;
- Riga 11: Il server indica che, con la sua risposta HTTP, sta inviando un documento text/html (riga 3) di 132 byte (riga 11). Quando esaminiamo la risposta alla richiesta [Action06] in Chrome, è vuota, come previsto. Probabilmente c'è una spiegazione, ma non so quale sia.
A causa del reindirizzamento, il browser effettua una nuova richiesta GET all'URL specificato nella riga 4 sopra, come si può vedere in Chrome alla riga 1 qui sotto:
3.10. Azione con un risultato di tipo [RedirectResult] - 2
Si consideri la seguente nuova azione:
// Action07
public RedirectResult Action07()
{
return new RedirectResult("/First/Action05",true);
}
Alla riga 4, abbiamo aggiunto un secondo parametro al costruttore [RedirectResult]. Si tratta di un valore booleano il cui valore predefinito è false. Se impostato su true, modifica la risposta HTTP inviata al client. Diventa:
Pertanto, il codice di risposta inviato al client è ora 301 Moved Permanently. Il reindirizzamento avviene come prima, ma indichiamo che questo reindirizzamento è permanente. Ciò consente ai motori di ricerca di sostituire il vecchio URL con quello nuovo nei loro risultati.
3.11. Azione con un risultato di tipo [RedirectToRouteResult]
Consideriamo la seguente nuova azione:
// Action08
public RedirectToRouteResult Action08()
{
return new RedirectToRouteResult("Default",new RouteValueDictionary(new {controller="First",action="Action05"}));
}
- Riga 2: L'azione restituisce un tipo [RedirectToRouteResult]. Questo tipo consente di reindirizzare un client a un URL specificato, non tramite una stringa come in precedenza, ma tramite un percorso.
I percorsi sono definiti in [App_Start/RouteConfig]. Attualmente ce n'è solo uno:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
- Alla riga 4, al client viene indicato di reindirizzarsi alla route denominata [Default] con la variabile controller impostata su "First" e la variabile action impostata su "Action05". Il sistema di routing genererà quindi l'URL di reindirizzamento /First/Action05. Ciò è mostrato nella risposta HTTP del server:
- riga 1: il reindirizzamento;
- riga 4: l'URL di reindirizzamento generato dal sistema di routing degli URL.
3.12. Azione con tipo di ritorno [void]
Consideriamo la seguente nuova azione:
// Action09
public void Action09()
{
string nom = Request.QueryString["nom"] ?? "inconnu";
Response.AddHeader("Content-Type", "text/plain");
Response.Write(string.Format("<h3>Action09</h3>nom={0}", nom));
}
- riga 2: l'azione non restituisce alcun risultato. Scrive direttamente nel flusso di risposta inviato al client;
- riga 4: recuperiamo un potenziale parametro denominato [name] dalla richiesta. È accessibile tramite la proprietà [Request] della classe [Controller] da cui il controller [First] eredita. Il parametro [name] passato nel modulo [/First/Action09?name=something] è disponibile in Request.QueryString["name"]. La sintassi della riga 4 è equivalente a:
- riga 5: la risposta inviata al client è accessibile tramite la proprietà [Response] della classe [Controller] da cui il controller [First] eredita;
- riga 5: impostiamo l'intestazione HTTP [Content-Type], che indica la natura del documento che il server sta per inviare al client. Qui, "text/plain" indica che il documento è testo semplice che non deve essere interpretato dal browser;
- riga 6: inseriamo una stringa di caratteri nel corpo della risposta. Abbiamo incluso dei tag HTML che non dovrebbero essere interpretati dal browser, poiché quest'ultimo avrà già ricevuto l'intestazione HTTP [Content-Type: text/plain]. È proprio questo che vogliamo verificare.
Compiliamo il progetto e richiediamo l'URL [/First/Action09?name=someone ][1] e poi l'URL [/First/Action09 ] [2]:
![]() |
Ora diamo un'occhiata alla risposta HTTP del server in Chrome:
- riga 3: vediamo l'intestazione HTTP che abbiamo impostato noi stessi nel codice dell'azione.
3.13. Un secondo controller
Creiamo un secondo controller nel progetto. Seguiremo il metodo descritto nella sezione 3.1, a pagina 36. Lo chiameremo [Second].

Il codice generato è il seguente:
namespace Exemple_01.Controllers
{
public class SecondController : Controller
{
//
// GET: /Second/
public ActionResult Index()
{
return View();
}
}
}
Modifichiamolo come segue:
using System.Text;
using System.Web.Mvc;
namespace Exemple_01.Controllers
{
public class SecondController : Controller
{
// /Second/Action01
public ContentResult Action01()
{
return Content("Contrôleur=Second, Action=Action01", "text/plain", Encoding.UTF8);
}
}
}
Quindi richiediamo l'URL [/Second/Action01] utilizzando un browser. Otteniamo la seguente risposta:

Questo URL è stato richiesto utilizzando una richiesta HTTP GET, come mostrato nei log HTTP relativi alla richiesta in Chrome:
L'URL può essere richiesto anche tramite una richiesta HTTP POST. Per dimostrarlo, utilizziamo nuovamente l'app [Advanced Rest Client]:
![]() |
- In [1], avvia l'applicazione (nella scheda [Applicazioni] di una nuova scheda di Chrome);
- in [2], seleziona l'opzione [Request];
- in [3], specifica l'URL richiesto;
- in [4], specificare che l'URL deve essere richiesto utilizzando una richiesta POST;
Attiviamo i log di Chrome (CTRL-I) per visualizzare la risposta HTTP del server. Quando clicchiamo su [Invia] per eseguire la richiesta precedente, lo scambio di dati HTTP è il seguente:
Il browser invia la seguente richiesta:
- riga 1: l'URL viene effettivamente richiesto con un POST;
- Riga 4: La dimensione in byte degli elementi inviati. Qui non ce ne sono.
La risposta HTTP del server è la seguente:
- riga 3: il server invia un documento di testo non formattato (semplice);
- riga 12: 148 caratteri.
Il documento inviato è il seguente:

Otteniamo lo stesso documento della richiesta GET.
3.14. Azione filtrata da un attributo
Creiamo la seguente nuova azione:
// /Second/Action02
[HttpPost]
public ContentResult Action02()
{
return Content("Contrôleur=Second, Action=Action02", "text/plain", Encoding.UTF8);
}
L'azione [Action02] è simile all'azione [Action01], ma specifica che è accessibile solo tramite una richiesta HTTP POST (riga 2). È possibile utilizzare altri attributi:
HttpGet | gestisce solo la richiesta GET |
HttpHead | gestisce solo la richiesta HEAD |
HttpOptions | supporta solo il comando OPTIONS |
HttpPut | supporta solo il comando PUT |
HttpDelete | viene utilizzato solo per il comando DELETE |
Richiediamo l'URL [/Second/Action02] direttamente nel browser. Viene quindi richiesto tramite un GET. Il browser visualizza quindi la seguente risposta:

La risposta HTTP del server era la seguente:
- Riga 1: Il codice HTTP 404 Not Found indica che il server non è riuscito a trovare il documento richiesto. In questo caso, l'azione [Action02] non è riuscita a gestire la richiesta GET perché gestisce solo richieste POST;
- Riga 3: La dimensione del documento restituito. Questa è la pagina che è stata visualizzata dal browser:

3.15. Recupero di elementi da una route
Nelle due azioni descritte sopra, abbiamo scritto qualcosa del tipo:
public ContentResult Action02()
{
return Content("Contrôleur=Second, Action=Action02", "text/plain", Encoding.UTF8);
}
I nomi del controller e dell'azione sono stati hard-coded nel codice. Se modifichiamo questi nomi, il codice non sarà più corretto. Possiamo accedere al controller e all'azione come segue:
// /Second/Action03
public ContentResult Action03()
{
string texte = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
return Content(texte, "text/plain", Encoding.UTF8);
}
Il percorso definito in [App_Start/RouteConfig] è il seguente:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Riga 3: I tre elementi del percorso possono essere recuperati utilizzando RouteData.Values["element"], dove element è uno tra [controller, action, id].
Richiediamo l'URL [http://localhost:49302/Second/Action03]:

Abbiamo recuperato con successo sia il nome del controller che quello dell'azione.











