Gestire le richieste con controller in ASP.NET Core MVC
I controller, le azioni e risultati delle azioni sono parti fondamentali dello sviluppo di app tramite ASP.NET Core MVC.
Che cos'è un controller?
Un controller viene usato per definire e raggruppare un set di azioni. Un'azione (o metodo di azione) è un metodo in un controller che gestisce richieste. I controller raggruppano azioni simili in modo logico. Questa aggregazione di azioni consente l'applicazione collettiva di set di regole comuni, ad esempio routing, memorizzazione nella cache e autorizzazione. Le richieste vengono mappate alle azioni tramite routing. I controller vengono attivati ed eliminati per ogni richiesta.
Per convenzione, le classi controller:
- Risiedere nella cartella Controller a livello radice del progetto.
- Ereditare da
Microsoft.AspNetCore.Mvc.Controller
.
Un controller è una classe di cui è possibile creare un'istanza, in genere pubblica, in cui almeno una delle condizioni seguenti è vera:
- Il nome della classe è suffisso con
Controller
. - La classe eredita da una classe il cui nome è suffisso con
Controller
. - L'attributo
[Controller]
viene applicato alla classe .
A una classe controller non deve essere associato un attributo [NonController]
.
I controller devono seguire il principio delle dipendenze esplicite. Per l'implementazione di questo principio esistono due approcci. Se più azioni del controller richiedono lo stesso servizio, prendere in considerazione l'uso dell'inserimento di costruttori per richiedere tali dipendenze. Se il servizio è richiesto da un solo metodo di azione, prendere in considerazione l'uso dell'inserimento di azioni per richiedere la dipendenza.
All'interno del modello Model-View-Controller, un controller è responsabile dell'elaborazione iniziale della richiesta e della creazione di istanze del modello. In genere, per le decisioni aziendali è consigliabile seguire il modello.
Il controller riceve il risultato di un'eventuale elaborazione del modello e restituisce la visualizzazione corretta e i dati associati oppure il risultato della chiamata API. Per altre informazioni, vedere Panoramica di ASP.NET Core MVC e Introduzione ad ASP.NET Core MVC e Visual Studio.
Il controller è un'astrazione a livello di interfaccia utente. Il suo compito è di verificare che i dati della richiesta siano validi e di scegliere la visualizzazione (o il risultato per un'API) da restituire. Nelle app con factoring corretto, il controller non include direttamente accesso ai dati o logica di business, ma delega la gestione di tali responsabilità a servizi specifici.
Definizione di azioni
I metodi pubblici in un controller, ad eccezione di quelli con l'attributo [NonAction]
, sono azioni. I parametri delle azioni sono associati a dati di richiesta e vengono convalidati tramite associazione di modelli. La convalida del modello viene eseguita per tutto ciò che è associato a un modello. Il valore della proprietà ModelState.IsValid
indica se l'associazione e la convalida dei modelli hanno avuto esito positivo.
I metodi di azione devono contenere la logica per il mapping di una richiesta a un problema di business. È di solito consigliabile rappresentare i problemi di business come servizi a cui il controller accede tramite inserimento di dipendenze. Le azioni eseguono quindi il mapping del risultato dell'azione di business a uno stato dell'applicazione.
Le azioni possono restituire qualsiasi valore, ma spesso restituiscono un'istanza di IActionResult
(o di Task<IActionResult>
per i metodi asincroni) che genera una risposta. Il metodo di azione è responsabile della scelta del tipo di risposta. Il risultato dell'azione esegue la risposta.
Metodi helper dei controller
I controller ereditano in genere da Controller, anche se questo non è obbligatorio. La derivazione da Controller
consente l'accesso a tre categorie di metodi helper:
1. Metodi che generano un corpo di risposta vuoto
Non è inclusa un'intestazione di risposta HTTP Content-Type
, poiché il corpo della risposta non ha contenuto da descrivere.
All'interno di questa categoria sono presenti due tipi di risultati: reindirizzamento e codice di stato HTTP.
Codice di stato HTTP
Questo tipo restituisce un codice di stato HTTP. Alcuni metodi helper di questo tipo sono
BadRequest
,NotFound
eOk
. Il metodoreturn BadRequest();
, ad esempio, quando viene eseguito genera un codice di stato 400. Quando metodi comeBadRequest
,NotFound
eOk
vengono sottoposti a overload, non sono più risponditori del codice di stato HTTP, poiché è in corso la negoziazione del contenuto.Reindirizzamento
Questo tipo restituisce un reindirizzamento a un'azione o a una destinazione (tramite
Redirect
,LocalRedirect
,RedirectToAction
oRedirectToRoute
).return RedirectToAction("Complete", new {id = 123});
, ad esempio, reindirizza aComplete
, passando un oggetto anonimo.Il tipo di risultato del reindirizzamento è diverso dal tipo del codice di stato HTTP principalmente per l'aggiunta di una intestazione della risposta HTTP
Location
.
2. Metodi che generano un corpo della risposta non vuoto con un tipo di contenuto predefinito
La maggior parte dei metodi helper di questa categoria includono una proprietà ContentType
, che consente di impostare l'intestazione della risposta Content-Type
in modo da descrivere il corpo della risposta.
All'interno di questa categoria sono presenti due tipi di risultato: visualizzazione e risposta formattata.
Visualizza
Questo tipo restituisce una visualizzazione che esegue il rendering HTML usando un modello.
return View(customer);
, ad esempio, passa un modello alla visualizzazione per eseguire il data binding.Risposta formattata
Questo tipo restituisce il formato JSON o un formato di scambio di dati simile per rappresentare un oggetto in un modo specifico.
return Json(customer);
, ad esempio, serializza l'oggetto specificato in formato JSON.Altri metodi comuni di questo tipo sono
File
ePhysicalFile
. Ad esempioreturn PhysicalFile(customerFilePath, "text/xml");
restituisce PhysicalFileResult.
3. Metodi che generano un corpo della risposta non vuoto formattato in un tipo di contenuto negoziato con il client
Questa categoria è più nota come negoziazione del contenuto. La negoziazione del contenuto viene applicata ogni volta che un'azione restituisce un ObjectResult tipo o un elemento diverso da un'implementazione IActionResult . Anche un'azione che restituisce un'implementazione non di IActionResult
(ad esempio, object
) restituisce una risposta formattata.
Alcuni metodi helper di questo tipo sono BadRequest
, CreatedAtRoute
e Ok
. Alcuni esempi di questi metodi sono, rispettivamente, return BadRequest(modelState);
, return CreatedAtRoute("routename", values, newobject);
e return Ok(value);
. Si noti che BadRequest
e Ok
eseguono la negoziazione del contenuto solo quando viene passato loro un valore. Se non viene loro passato alcun valore, fungono invece da tipi di risultato codice di stato HTTP. Il metodo CreatedAtRoute
, d'altra parte, esegue sempre la negoziazione del contenuto, perché tutti gli overload di questo metodo richiedono che venga passato un valore.
Problemi di montaggio incrociato
Le applicazioni condividono in genere parti del flusso di lavoro. Tra gli esempi possibili, un'app che richiede l'autenticazione per accedere al carrello o un'app che memorizza nella cache i dati di alcune pagine. Per eseguire della logica prima o dopo un metodo di azione, usare un filtro. L'uso di filtri su problemi di montaggio incrociato può ridurre la duplicazione.
La maggior parte degli attributi di filtro, ad esempio [Authorize]
, può essere applicata a livello di controller o di azione, a seconda del livello di granularità desiderato.
La gestione degli errori e la memorizzazione nella cache delle risposte rappresentano spesso problemi di montaggio incrociato:
Molti problemi di montaggio incrociato possono essere gestiti tramite filtri o middleware personalizzato.