Utilizzare un servizio REST con HttpClient
Molti servizi Web moderni implementano l'architettura REST. Questa struttura consente a un servizio Web di esporre operazioni e dati attraverso una serie di endpoint ben definiti. Le richieste inviate dalle app client a un servizio Web REST per recuperare, modificare, creare o eliminare dati usano un set predefinito di verbi. Un servizio Web REST risponde a queste richieste in modo standard. Questo approccio semplifica la creazione di app client.
Il modello REST è basato sul protocollo HTTP. Un'applicazione .NET MAUI può inviare richieste a un servizio Web REST usando la classe HttpClient
. In questa unità verranno fornite informazioni su HttpClient
e su come usare questa unità per interagire con un servizio Web REST.
Che cos'è la classe HttpClient?
HttpClient
è una classe .NET che un'app può usare per inviare richieste HTTP e ricevere risposte HTTP da un servizio Web REST. Un set di URI identifica le risorse esposte dal servizio Web. Un URI combina l'indirizzo del servizio Web con il nome di una risorsa disponibile a tale indirizzo.
La classe HttpClient
usa un'API basata su attività per le prestazioni e consente di accedere alle informazioni contenute nei messaggi di richiesta, quali intestazioni HTTP e codici di stato, così come corpi dei messaggi che contengono i dati effettivi da inviare e ricevere.
La classe HttpClient
è disponibile nello spazio dei nomi System.Net.Http
. Un'app può creare un oggetto HttpClient
utilizzando il costruttore predefinito:
using System.Net.Http;
...
var client = new HttpClient();
Eseguire operazioni CRUD con un oggetto HttpClient
Un servizio Web REST consente a un client di eseguire operazioni su dati tramite un set di verbi HTTP. Lo scopo del verbo HTTP è indicare l'azione desiderata da eseguire su una risorsa. I verbi HTTP sono molti, ma i quattro più comuni sono POST
, GET
, PUT
e DELETE
. Un servizio può implementare questi verbi per consentire a un'applicazione client di gestire il ciclo di vita degli oggetti eseguendo operazioni di creazione, lettura, aggiornamento ed eliminazione (CRUD) nel modo seguente:
Il verbo
POST
indica che si vuole creare una nuova risorsa.Il verbo
GET
indica che si vuole recuperare una risorsa.Il verbo
PUT
indica che si vuole aggiornare una risorsa.Il verbo
DELETE
indica che si vuole eliminare una risorsa.
Creare una nuova risorsa con HttpClient
Per creare una nuova risorsa usando HttpClient
, è possibile usare il metodo SendAsync
per passarla a un oggetto HttpRequestMessage
.
HttpRequestMessage
deve modellare la richiesta inviata al servizio Web. Specificare il verbo HTTP, l'URL del servizio Web e popolare qualsiasi payload da inviare tramite la proprietà HttpRequestMessage.Content
.
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, url);
message.Content = JsonContent.Create<Part>(part);
HttpResponseMessage response = await client.SendAsync(message);
Questo frammento di codice esegue le attività seguenti:
- Crea un'istanza di
HttpClient
chiamata client usata per inviare un messaggio. - Crea un'istanza di
HttpRequestMessage
chiamata messaggio usata per modellare il messaggio. Il messaggio contiene il verbo HTTP e l'URL. - Imposta la proprietà
Content
diHttpRequestMessage
, usando la funzioneJsonContent.Create
. Tale funzione serializza automaticamente la parte variabile in JSON adatta per l'invio al servizio Web. - Il messaggio viene inviato usando l'oggetto
HttpClient
. QuandoHttpResponseMessage
viene restituito contiene informazioni come il codice di stato e le informazioni restituite dal servizio Web.
Leggere una risorsa con HttpClient
È possibile leggere una risorsa da un servizio Web usando la stessa tecnica descritta in precedenza, ma non inizializzare HttpRequestMessage
con HttpMethod.Get
. Tuttavia, con HttpClient
sono disponibili un paio di metodi pratici che garantiscono tasti di scelta rapida.
Per leggere una risorsa con HTTPClient
, usare il metodo GetStringAsync
come illustrato nell'esempio seguente:
HttpClient client = new HttpClient();
string text = await client.GetStringAsync("https://...");
Il metodo GetStringAsync
accetta un URI che fa riferimento alla risorsa e restituisce una risposta come stringa. La stringa di risposta è la risorsa richiesta dall'app. Il formato dei dati della risposta è quello predefinito per il servizio richiesto, ad esempio JSON o XML. Un'app può indicare al servizio Web che i dati devono essere restituiti in un formato specifico aggiungendo l'intestazione MediaTypeWithQualityHeaderValue
. Ad esempio, se l'app richiede che i dati vengano inviati in formato JSON, può essere usato il codice seguente:
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
In questo esempio il risultato viene restituito come stringa e contiene solo il corpo del messaggio di risposta. Per ottenere l'intera risposta, incluse intestazioni, corpo e codice di stato, chiamare il metodo GetAsync
. I dati vengono restituiti come un oggetto HttpResponseMessage
.
Aggiornare una risorsa con HttpClient
Per aggiornare una risorsa con HttpClient
, usare HttpRequestMessage
inizializzato con un verbo PUT. Il codice seguente è simile a quello necessario per creare una nuova risorsa:
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Put, url);
message.Content = JsonContent.Create<Part>(part);
HttpResponseMessage response = await client.SendAsync(message);
Nota
La differenza fondamentale tra POST
e PUT
è l’idempotenza. Se la richiesta PUT
viene ripetuta più volte, la risorsa verrà aggiornata con i soliti dati e l'effetto sarà lo stesso come se la richiesta fosse stata inviata una sola volta. Se la stessa richiesta POST
viene inviata più volte, porterà il servizio REST a creare più copie della risorsa.
Eliminare una risorsa con HttpClient
Per eliminare una risorsa usando HttpClient
, chiamare SendAsync
con HttpRequestMessage
inizializzato con un verbo DELETE:
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Delete, url);
HttpResponseMessage response = await client.SendAsync(message);
La risposta contiene le intestazioni, il codice di stato e l'oggetto eliminato.
Gestire le risposte da una richiesta
Tutte le richieste HTTP restituiscono un messaggio di risposta. I dati nella risposta dipendono dal verbo inviato dall'app. Ad esempio, il corpo della risposta di una richiesta GET
HTTP contiene i dati per la risorsa richiesta.
Il corpo della risposta di una richiesta POST
restituisce una copia della risorsa creata, ma il corpo della risposta di una richiesta PUT
deve essere vuoto.
È consigliabile controllare e gestire sempre il codice di stato nel messaggio di risposta. Se questo codice di stato si trova nell'intervallo 200 (200, 201, 202 e così via), l'operazione è considerata riuscita, anche se in seguito potrebbero essere necessarie ulteriori informazioni.
Un codice di stato nell'intervallo 300 indica che la richiesta potrebbe essere stata reindirizzata dal servizio Web a un indirizzo diverso, probabilmente come risultato dello spostamento di una risorsa in una posizione diversa.
Un codice di stato nell'intervallo 400 indica un errore del client o dell'applicazione. Ad esempio, il codice di stato 403 indica che il servizio Web richiede l'autenticazione dell'utente, che però non è stata effettuata dall’app. Il codice di stato 404 si verifica quando l'app tenta di accedere a una risorsa che non esiste.
I codici di stato nell'intervallo 500 indicano un errore sul lato server. Ad esempio, il servizio non è disponibile o è troppo occupato per gestire la richiesta.
L'oggetto HttpResponseMessage
restituito da una richiesta inviata tramite un oggetto HttpClient
può astrarre gran parte della complessità della gestione dei diversi codici di stato. Questo frammento di codice mostra come verificare che il codice di stato in un messaggio di risposta indichi l'esito positivo e come gestire i codici di stato che indicano un certo tipo di errori.
static readonly HttpClient client = new HttpClient();
...
// Call asynchronous network methods in a try/catch block to handle exceptions.
try
{
//... Initiate the HttpRequest
HttpResponseMessage response = await client.SendAsync(msg);
response.EnsureSuccessStatusCode(); // Check that the status code is in the 200 range. Throw an HttpRequestException if not
string responseBody = await response.Content.ReadAsStringAsync();
... // Handle the response
}
catch(HttpRequestException e)
{
... // Handle any status codes that indicate an error.
// The status code is available in the field e.StatusCode
}