Esercizio - Aggiungere un controller

Completato

Un controller è una classe pubblica con uno o più metodi pubblici chiamati azioni. Per convenzione, un controller viene posizionato nella directory Controllers della radice del progetto. Le azioni vengono esposte come endpoint HTTP all'interno del controller dell'API Web.

Creare un controller

  1. Selezionare la cartella Controllers in Visual Studio Code e aggiungere un nuovo file denominato Pizza.cs.

    Screenshot of Visual Studio Code that shows adding a new file to the Controllers folder.

    Viene creato un file di classe vuoto denominato PizzaController.cs nella directory Controllers. Il nome di directory Controllers è una convenzione. Il nome della directory deriva dall'architettura Model-View-Controller usata dall'API Web.

    Nota

    Per convenzione, i nomi delle classi dei controller hanno il suffisso Controller.

  2. Aggiungere il codice seguente a Controllers/PizzaController.cs. Salva le modifiche.

    using ContosoPizza.Models;
    using ContosoPizza.Services;
    using Microsoft.AspNetCore.Mvc;
    
    namespace ContosoPizza.Controllers;
    
    [ApiController]
    [Route("[controller]")]
    public class PizzaController : ControllerBase
    {
        public PizzaController()
        {
        }
    
        // GET all action
    
        // GET by Id action
    
        // POST action
    
        // PUT action
    
        // DELETE action
    }
    

    Come si è appreso in precedenza, questa classe deriva da ControllerBase, la classe di base per l'uso delle richieste HTTP in ASP.NET Core. Include anche i due attributi standard già presentati, [ApiController] e [Route]. Come in precedenza, l'attributo [Route] definisce un mapping con il token [controller]. Poiché questa classe controller è denominata PizzaController, questo controller gestisce le richieste a https://localhost:{PORT}/pizza.

Ottenere tutte le pizze

Il primo verbo REST da implementare è GET, con il quale un client può recuperare tutte le pizze dall'API. Si può usare l'attributo [HttpGet] predefinito per definire un metodo che restituirà le pizze dal servizio.

Sostituire il commento // GET all action in Controllers/PizzaController.cs con il codice seguente:

[HttpGet]
public ActionResult<List<Pizza>> GetAll() =>
    PizzaService.GetAll();

L'azione precedente:

  • Risponde solo al verbo HTTP GET, come indicato dall'attributo [HttpGet].
  • Restituisce un'istanza ActionResult di tipo List<Pizza>. Il tipo ActionResult è la classe di base per tutti i risultati dell'azione in ASP.NET Core.
  • Esegue una query sul servizio per tutte le pizze e restituisce automaticamente i dati con un valore Content-Type di application/json.

Recuperare una singola pizza

Il client potrebbe anche richiedere di ottenere informazioni su una pizza specifica anziché l'intero elenco. È possibile implementare un'altra azione GET che richiede un parametro id. Si può usare l'attributo [HttpGet("{id}")] predefinito per definire un metodo che restituirà le pizze dal servizio. La logica di routing registra [HttpGet] (senza id) e [HttpGet("{id}")] (con id) come due route diverse. È quindi possibile scrivere un'azione separata per recuperare un singolo elemento.

Sostituire il commento // GET by Id action in Controllers/PizzaController.cs con il codice seguente:

[HttpGet("{id}")]
public ActionResult<Pizza> Get(int id)
{
    var pizza = PizzaService.Get(id);

    if(pizza == null)
        return NotFound();

    return pizza;
}

L'azione precedente:

  • Risponde solo al verbo HTTP GET, come indicato dall'attributo [HttpGet].
  • Richiede che il valore del parametro id sia incluso nel segmento dell'URL dopo pizza/. Tenere presente che l'attributo [Route] a livello del controller ha definito il modello /pizza.
  • Esegue una query sul database per cercare una pizza corrispondente al parametro id specificato.

Viene eseguito il mapping di ogni istanza di ActionResult usata nell'azione precedente al codice di stato HTTP corrispondente nella tabella seguente:

ASP.NET Core
ASP.NET Core
Codice di stato HTTP Descrizione
Ok è implicito 200 La cache in memoria contiene un prodotto corrispondente al parametro id specificato.
Il prodotto è incluso nel corpo della risposta nel tipo di supporto definito nell'intestazione della richiesta HTTP accept (JSON per impostazione predefinita).
NotFound 404 La cache in memoria non contiene un prodotto corrispondente al parametro id specificato.

Compilare ed eseguire il nuovo controller

Compilare e avviare l'API Web eseguendo il comando seguente:

dotnet run

Testare il controller con il file .http

  1. Aprire ContosoPizza.http

  2. Aggiungere un nuovo GET per chiamare l'endpoint Pizza sotto il ### seperator:

    GET {{ContosoPizza_HostAddress}}/pizza/
    Accept: application/json
    
    ###
    
  3. Selezionare il comando Send Request sopra questa nuova chiamata GET .

    Il comando precedente restituisce un elenco di tutte le pizze in JSON:

    HTTP/1.1 200 OK
    Connection: close
    Content-Type: application/json; charset=utf-8
    Date: Wed, 17 Jan 2024 16:57:09 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    [
        {
            "id": 1,
            "name": "Classic Italian",
            "isGlutenFree": false
        },
        {
            "id": 2,
            "name": "Veggie",
            "isGlutenFree": true
        }
    ]   
    
  4. Per eseguire una query per una singola pizza è possibile effettuare un'altra richiesta GET, passando però un parametro id con il comando seguente:

    GET {{ContosoPizza_HostAddress}}/pizza/1
    Accept: application/json
    
    ###
    

    Il comando precedente restituisce Classic Italian con l'output seguente:

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Date: Fri, 02 Apr 2021 21:57:57 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    {
        "id": 1,
        "name": "Classic Italian",
        "isGlutenFree": false
    }
    
  5. L'API gestisce anche le situazioni in cui l'elemento non esiste. Chiamare di nuovo l'API, ma passare un parametro id di pizza non valido con il comando seguente:

    GET {{ContosoPizza_HostAddress}}/pizza/5
    Accept: application/json
    
    ###
    

    Il comando precedente restituisce un errore 404 Not Found con l'output seguente:

    HTTP/1.1 404 Not Found
    Content-Type: application/problem+json; charset=utf-8
    Date: Fri, 02 Apr 2021 22:03:06 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    {
        "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
        "title": "Not Found",
        "status": 404,
        "traceId": "00-ec263e401ec554b6a2f3e216a1d1fac5-4b40b8023d56762c-00"
    }
    

A questo punto è stata completata l'implementazione dei verbi GET. Nell'unità successiva sarà possibile aggiungere altre azioni a PizzaController per supportare operazioni CRUD sui dati per le pizze.

Facoltativo: testare il controller con REPL HTTP della riga di comando

  1. Aprire il terminale httprepl esistente o aprire un nuovo terminale integrato da Visual Studio Code scegliendo Terminale>Nuovo terminale dal menu principale.

  2. Connettersi all'API Web eseguendo il comando seguente:

    httprepl https://localhost:{PORT}
    

    In alternativa, eseguire questo comando in qualsiasi momento durante l'esecuzione di HttpRepl:

    connect https://localhost:{PORT}
    
  3. Per visualizzare il nuovo endpoint Pizza disponibile, eseguire il comando seguente:

    ls
    

    Il comando precedente rileva tutte le API disponibili nell'endpoint connesso. Verrà visualizzato il codice seguente:

     https://localhost:{PORT}/> ls
     .                 []
     Pizza             [GET]
     WeatherForecast   [GET]
    
  4. Passare all'endpoint Pizza eseguendo questo comando:

    cd Pizza
    

    Il comando precedente mostra un output di API disponibili per l'endpoint Pizza:

    https://localhost:{PORT}/> cd Pizza
    /Pizza    [GET]
    
  5. Effettuare una richiesta GET in HttpRepl usando questo comando:

    get
    

    Il comando precedente restituisce un elenco di tutte le pizze in JSON:

      HTTP/1.1 200 OK
      Content-Type: application/json; charset=utf-8
      Date: Fri, 02 Apr 2021 21:55:53 GMT
      Server: Kestrel
      Transfer-Encoding: chunked
    
      [
          {
              "id": 1,
              "name": "Classic Italian",
              "isGlutenFree": false
          },
          {
              "id": 2,
              "name": "Veggie",
              "isGlutenFree": true
          }
      ]
    
  6. Per eseguire una query per una singola pizza è possibile effettuare un'altra richiesta GET, passando però un parametro id con il comando seguente:

    get 1
    

    Il comando precedente restituisce Classic Italian con l'output seguente:

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Date: Fri, 02 Apr 2021 21:57:57 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    {
        "id": 1,
        "name": "Classic Italian",
        "isGlutenFree": false
    }
    
  7. L'API gestisce anche le situazioni in cui l'elemento non esiste. Chiamare di nuovo l'API, ma passare un parametro id di pizza non valido con il comando seguente:

    get 5
    

    Il comando precedente restituisce un errore 404 Not Found con l'output seguente:

    HTTP/1.1 404 Not Found
    Content-Type: application/problem+json; charset=utf-8
    Date: Fri, 02 Apr 2021 22:03:06 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
    
    {
        "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
        "title": "Not Found",
        "status": 404,
        "traceId": "00-ec263e401ec554b6a2f3e216a1d1fac5-4b40b8023d56762c-00"
    }
    
  8. Tornare al terminale dotnet nell'elenco a discesa in Visual Studio Code e arrestare l'API Web premendo CTRL+C sulla tastiera.

A questo punto è stata completata l'implementazione dei verbi GET. Nell'unità successiva sarà possibile aggiungere altre azioni a PizzaController per supportare operazioni CRUD sui dati per le pizze.