Esercizio - Utilizzare un servizio REST con HttpClient

Completato

Come parte dell'app usata dai tecnici nelle visite del sito dei clienti, è necessario aggiungere una funzionalità che consente a un tecnico di cercare i dettagli dei componenti elettrici. Queste informazioni verranno memorizzate in un database e saranno accessibili tramite un servizio Web REST. È stato anche chiesto di fornire un'interfaccia che consente a un amministratore di creare, rimuovere e modificare i dettagli delle parti contenute nel database usando lo stesso servizio Web REST.

In questo esercizio si distribuirà il servizio Web REST in Azure e quindi si verificherà che sia possibile accedervi usando un Web browser. Si aggiungeranno quindi funzionalità a un'app esistente che usa il servizio Web REST per recuperare, aggiungere, eliminare e aggiornare i dettagli dei componenti elettrici.

L'esercizio viene eseguito nell'ambiente sandbox di Azure.

Suggerimento

È possibile usare il pulsante Copia per copiare i comandi negli Appunti. Per incollare, fare clic con il pulsante destro del mouse su una nuova riga nel terminale di Cloud Shell e scegliere Incolla oppure usare i tasti di scelta rapida MAIUSC+INS (⌘+V in macOS).

Distribuire il servizio Web REST Parts

  1. Nella finestra Cloud Shell eseguire questo comando per clonare il repository contenente il codice per l'esercizio, incluso il servizio Web REST Parts:

    git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
    
  2. Passare alla cartella Consume-REST-services:Move to the Consume-REST-services folder:

    cd mslearn-dotnetmaui-consume-rest-services/src
    
  3. Eseguire il comando seguente per distribuire il servizio Web part usando la sandbox di Azure Cloud Shell. Questo comando rende il servizio disponibile tramite un URL univoco. Annotare questo URL quando viene visualizzato. L'app verrà configurata per connettersi al servizio Web tramite questo URL.

    bash initenvironment.sh
    

Esaminare il codice per il servizio Web

Nota

Eseguirai il resto di questo esercizio nel computer di sviluppo locale.

  1. Nel computer aprire una finestra del prompt dei comandi e clonare il repository per questo esercizio. Il codice si trova nel repository net-maui-learn-consume-rest-services.

    git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
    

    Nota

    È consigliabile clonare o scaricare il contenuto dell'esercizio in un percorso di cartella breve, ad esempio C:\dev, per evitare che i file generati dalla compilazione superino la lunghezza massima del percorso.

  2. Passare alla cartella src\webservice\PartsServer nel clone del repository e aprire la soluzione PartsServer.sln usando Visual Studio o la cartella in Visual Studio Code. Questa soluzione contiene una copia del codice per il servizio Web distribuito in Azure nella procedura precedente.

  3. Nella finestra Esplora soluzioni espandere la cartella Models. La cartella contiene due file:

    • Part.cs. La classe Part rappresenta un componente come fornito dal servizio Web REST. I campi includono l'ID, il nome e il tipo del componente, la data di disponibilità (quando il componente è stato fornito la prima volta) e un elenco di fornitori. La proprietà Href restituisce l'URI relativo del componente e un client REST può utilizzare questo URI per fare riferimento a questo componente specifico nel servizio Web REST. La proprietà Suppliers restituisce l'elenco di fornitori del componente in forma di stringa.

    • PartsFactory.cs. La classe PartsFactory inizializza l'elenco di componenti forniti dal servizio, utilizzando un piccolo set di valori hardcoded. Nell'ambiente reale, questi dati vengono recuperati da un database.

  4. Nella finestra Esplora soluzioni espandere la cartella Controllers. La cartella contiene i file seguenti:

    • PartsController.cs. La classe PartsController implementa l'API Web per il servizio. Include metodi che consentono a un'applicazione client di recuperare un elenco di tutti i componenti (Get), di individuare i dettagli di un componente specifico tramite il relativo ID (la versione di overload di Get), di aggiornare i dettagli di un componente (Put), di aggiungere un nuovo componente all'elenco (Post) e di rimuovere un componente dall'elenco (Delete).

    • LoginController.cs. La classe LoginController implementa una semplice forma di autenticazione per il servizio Web. Un'app deve inviare una richiesta GET HTTP a questo controller, che restituisce un token di autorizzazione. Tale token consente di autenticare le richieste inviate a PartsController.

    • BaseController.cs. La classe BaseController contiene la logica utilizzata per autenticare le richieste. La classe PartsController eredita da questa classe. Se il client tenta di chiamare metodi nella classe PartsController senza fornire un token di autenticazione valido, i metodi restituiscono una risposta HTTP 401 (mancata autorizzazione).

Esaminare il codice per l'app client .NET MAUI

Questo modulo usa .NET 8.0 SDK. Assicurarsi di avere installato .NET 8.0 eseguendo il comando seguente nel terminale dei comandi preferito:

dotnet --list-sdks

Verrà visualizzato un output simile all'esempio seguente:

6.0.317 [C:\Program Files\dotnet\sdk]
7.0.401 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]

Assicurarsi che sia elencata una versione che inizia con 8. Se il comando non è presente nell'elenco o non viene trovato, installare la versione più recente di .NET 8.0 SDK.

  1. Chiudere la soluzione PartsServer e aprire la soluzione PartsClient nella cartella src\client\PartsClient nel repository clonato. Tale soluzione contiene un'implementazione parziale di un'app client .NET MAUI che usa il servizio Web PartsServer.

  2. Nella finestra Esplora soluzioni espandere la cartella Dati. La cartella contiene il codice per due classi:

    • PartsManager.cs. La classe PartsManager fornisce i metodi utilizzati dall'app client per interagire con il servizio Web REST. La classe è attualmente incompleta e il codice necessario viene aggiunto nel corso dell'esercizio. Al termine, il metodo GetClient si connette al servizio Web REST. Il metodo GetAll restituisce un elenco di componenti dal servizio Web REST. Il metodo Add aggiunge un nuovo componente all'elenco di componenti gestiti dal servizio Web REST. Il metodo Update modifica i dettagli di una parte archiviata dal servizio Web REST e il metodo Delete rimuove una parte.

    • Part.cs. La classe Part modella un componente archiviato nel database. Espone le proprietà che un'applicazione può usare per accedere ai campi PartID, PartName, PartAvailableDate, PartType e PartSuppliers. La classe fornisce anche un metodo di utilità denominato SupplierString che consente a un'applicazione di recuperare una stringa formattata contenente i nomi dei fornitori.

  3. Nella finestra Esplora soluzioni espandere la cartella Pages. La cartella contiene il markup e il codice per due pagine:

    • PartsPage.xaml. Questa pagina utilizza un layout CollectionView con un oggetto DataTemplate per visualizzare i dettagli dei componenti disponibili come elenco. L'oggetto DataTemplate utilizza l'associazione dati per connettere i dati visualizzati ai componenti recuperati dal servizio Web. È possibile selezionare una riga in CollectionView per modificare una parte in AddPartPage oppure selezionare il pulsante Aggiungi nuova parte per aggiungere una nuova parte.

    • AddPartPage.xaml. Questa pagina consente agli utenti di immettere e salvare i dettagli per una nuova parte. Gli utenti possono specificare il nome della parte, il tipo di parte e un fornitore iniziale. L'ID componente e la data di disponibilità parziale vengono generati automaticamente.

  4. Nella finestra Esplora soluzioni espandere la cartella ViewModels. Questa cartella contiene due classi: AddPartViewModel.cs e PartsViewModel.cs. Questi sono i modelli di visualizzazione per le rispettive pagine e contengono proprietà e logica che la pagina deve visualizzare e modificare i dati.

Accedere al servizio

Il servizio REST richiede di effettuare prima l'accesso per ottenere un token. L'autenticazione dell'utente non è prevista. Chiamare prima un endpoint specifico per ottenere un token di autorizzazione, quindi inviare di nuovo il token al server in ogni richiesta successiva nell'intestazione HTTP.

  1. Aprire il file PartsManager.cs nella cartella Data.

  2. Aggiungere i campi statici BaseAddress e Url alla classe PartsManager come definito nel frammento di codice seguente. Sostituire il testo URL GOES HERE con l'URL del servizio Web REST annotato in precedenza:

    public class PartsManager
    {
        static readonly string BaseAddress = "URL GOES HERE";
        static readonly string Url = $"{BaseAddress}/api/";
        ...
    }
    
  3. Aggiungere il campo seguente alla classe, dopo il campo Url. Il campo contiene il token di autorizzazione restituito quando l'utente effettua l'accesso:

    private static string authorizationKey;
    
  4. Trovare il metodo GetClient. Questo metodo genera attualmente un'eccezione NotImplementedException. Sostituire il codice esistente nel metodo con il codice seguente. Questo codice crea un oggetto HttpClient , quindi invia una richiesta all'endpoint di accesso del servizio Web REST. Il servizio deve rispondere con un messaggio che contiene il token di autorizzazione. Deserializzare il token e aggiungerlo come intestazione della richiesta di autorizzazione predefinita per le richieste successive inviate tramite l'oggetto HttpClient:

    private static async Task<HttpClient> GetClient()
    {
        if (client != null)
            return client;
    
        client = new HttpClient();
    
        if (string.IsNullOrEmpty(authorizationKey))
        {                
            authorizationKey = await client.GetStringAsync($"{Url}login");
            authorizationKey = JsonSerializer.Deserialize<string>(authorizationKey);
        }
    
        client.DefaultRequestHeaders.Add("Authorization", authorizationKey);
        client.DefaultRequestHeaders.Add("Accept", "application/json");
    
        return client;
    }
    

Eseguire un'operazione GET per recuperare informazioni per i componenti

  1. Nel file PartsManager.cs individuare il metodo GetAll. Si tratta di un metodo asincrono che restituisce un elenco enumerabile di componenti. Questo metodo non è ancora implementato.

  2. In questo metodo eliminare il codice che genera l'eccezione NotImplementedException.

  3. Verificare che il dispositivo disponga di connettività Internet tramite la classe Connectivity. Se Internet non è presente, restituisce un oggetto vuoto List<Part>.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return new List<Part>();
    
  4. Chiamare il metodo GetClient per recuperare un oggetto HttpClient da utilizzare. Tenere presente che GetClient è asincrono, quindi usare l'operatore await per acquisire l'oggetto restituito dal metodo.

  5. Chiamare il metodo GetStringAsync dell'oggetto HttpClient e fornire l'URL di base per recuperare una matrice di componenti dal servizio Web REST. I dati vengono restituiti in modo asincrono come stringa JSON.

  6. Deserializzare la stringa JSON restituita da questo metodo in un elenco di oggetti Part usando il metodo JsonSerializer.Deserialize . Restituire l'elenco al chiamante.

    Il metodo completo dovrebbe essere simile al seguente:

    public static async Task<IEnumerable<Part>> GetAll()
    {
        if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
            return new List<Part>();
    
        var client = await GetClient();
        string result = await client.GetStringAsync($"{Url}parts");
    
        return JsonSerializer.Deserialize<List<Part>>(result, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
            });                     
    }
    
  7. Compilare ed eseguire l'app. All'avvio dell'app, viene visualizzata la pagina Part List e dovrebbe essere visualizzato un elenco di componenti recuperati dal metodo GetAll. L'immagine seguente mostra l'app in esecuzione su Android:

    A screenshot of the Parts Client app running on Android showing a list of parts.

  8. Al termine dell'esplorazione dei dati, chiudere l'app e tornare a Visual Studio o Visual Studio Code.

Eseguire un'operazione POST per aggiungere un nuovo componente al database

  1. Nella classe PartsManager individuare il metodo Add. Tale metodo include parametri per il nome e il tipo del componente e per un fornitore. Il metodo è asincrono. Lo scopo del metodo consiste nell'inserire una nuova parte nel database e restituire un oggetto Part che rappresenta l'elemento appena creato.

  2. Eliminare il codice esistente nel metodo.

  3. Verificare che il dispositivo disponga di connettività Internet tramite la classe Connectivity. Se Internet non è presente, restituisce un oggetto vuoto Part.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return new Part();
    
  4. Creare un nuovo oggetto Part. Popolare i campi con i dati passati:

    • Impostare il campo PartID su una stringa vuota. Questo ID verrà generato dal servizio Web REST.
    • Creare un nuovo oggetto List per contenere il nome del fornitore.
    • Impostare il campo PartAvailableDate su DateTime.Now.
    • Ottenere un client HTTP dal metodo GetClient.
    var part = new Part()
    {
        PartName = partName,
        Suppliers = new List<string>(new[] { supplier }),
        PartID = string.Empty,
        PartType = partType,
        PartAvailableDate = DateTime.Now.Date
    };
    
  5. Chiamare il metodo GetClient per recuperare un oggetto HttpClient da utilizzare.

  6. Creare un oggetto HttpRequestMessage. L'oggetto consente di modellare la richiesta inviata al servizio Web. Avviarlo con parametri che indicano il verbo HTTP da utilizzare e l'URL del servizio Web con cui comunicare.

    var msg = new HttpRequestMessage(HttpMethod.Post, $"{Url}parts");
    
  7. È necessario inviare un payload al servizio Web con le informazioni dell'oggetto Part da creare. Tale payload verrà serializzato in JSON. Il payload JSON viene aggiunto alla proprietà HttpRequestMessage.Content e serializzato con il metodo JsonContent.Create.

    msg.Content = JsonContent.Create<Part>(part);
    
  8. Inviare ora il messaggio al servizio Web con la funzione HttpClient.SendAsync. Tale funzione restituirà un oggetto HttpResponseMessage che contiene informazioni sull'operazione sul server, ad esempio i codici di risposta HTTP e le informazioni passate dal server.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    

    Si noti che il precedente usa il response.EnsureSuccessStatusCode metodo . Se viene restituito un codice di stato diverso da HTTP 2xx, viene visualizzato un errore.

  9. Se il servizio Web restituisce informazioni, ad esempio un oggetto serializzato in JSON, è possibile leggerle in HttpResponseMessage. È quindi possibile deserializzare l'oggetto JSON usando JsonSerializer.Deserialize.

    var returnedJson = await response.Content.ReadAsStringAsync();
    
    var insertedPart = JsonSerializer.Deserialize<Part>(returnedJson, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
            });
    
  10. Viene restituito, infine, il nuovo oggetto Part inserito.

    return insertedPart;
    
  11. Compilare ed eseguire l'app. Selezionare il pulsante Aggiungi nuovo componente e immettere un nome, un tipo e un fornitore per creare un nuovo componente. Seleziona Salva. Verrà richiamato il metodo Add nella classe PartsManager per creare il nuovo componente nel servizio Web. Se l'operazione ha esito positivo, la pagina dell'elenco di componenti viene nuovamente visualizzata con il nuovo componente nella parte inferiore dell'elenco.

    A screenshot of the app running after a new part has been added. The new part is at the bottom of the list.

  12. Al termine dell'esplorazione dei dati, chiudere l'app e tornare a Visual Studio o Visual Studio Code.

Eseguire un'operazione PUT per aggiornare i dettagli di un componente presente nel database

  1. Nella classe PartsManager individuare il metodo Update. Si tratta di un metodo asincrono che accetta un oggetto Part come parametro. Il metodo non ha un valore restituito esplicito. Il tipo restituito, tuttavia, è Task, in modo che le eccezioni vengano restituite correttamente al chiamante. Implementare la funzionalità PUT.

  2. Eliminare il codice esistente.

  3. Come in precedenza, verificare la disponibilità di una connessione Internet.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return;
    
  4. Creare un nuovo oggetto HttpRequestMessage, specificando questa un'operazione PUT e l'URL per l'aggiornamento dei componenti.

    HttpRequestMessage msg = new(HttpMethod.Put, $"{Url}parts/{part.PartID}");
    
  5. Impostare la proprietà Content di HttpRequestMessage tramite la funzione JsonContent.Create e il parametro part passato alla funzione.

    msg.Content = JsonContent.Create<Part>(part);
    
  6. Ottenere un client HTTP dal metodo GetClient.

    var client = await GetClient();
    
  7. Inviare la richiesta con HttpClient e quindi verificare che sia stata completata correttamente.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    
  8. Compilare ed eseguire l'app. Selezionare una delle parti dall'elenco. Verrà visualizzata la pagina AddPart , questa volta con le proprietà già compilate. Aggiornare gli elementi desiderati.

  9. Seleziona Salva. Viene chiamato il metodo Update nella classe PartsManager per inviare le modifiche al servizio Web. Se l'operazione ha esito positivo, la pagina dell'elenco di componenti viene nuovamente visualizzata.

    A screenshot of the app running with the first item in the list updated.

    Nota

    Il componente aggiunto nell'attività precedente non viene visualizzato nella pagina Part List. I dati usati dall'app vengono reimpostati su un elenco di parti predefinite ogni volta che viene eseguita l'app. Ciò consente di garantire la coerenza dei test dell'app.

Eseguire un'operazione DELETE per rimuovere i dettagli di un componente presente nel database

  1. Nella classe PartsManager individuare il metodo Delete. Si tratta di un metodo asincrono che accetta una stringa partId e restituisce un oggetto Task.

  2. Eliminare il codice esistente.

  3. Verificare la disponibilità di una connessione Internet.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return;
    
  4. Creare un nuovo oggetto HttpRequestMessage. Solo ora specificare il verbo HTTP DELETE e l'URL per eliminare un componente.

    HttpRequestMessage msg = new(HttpMethod.Delete, $"{Url}parts/{partID}");
    
  5. Ottenere un client HTTP con il metodo GetClient.

    var client = await GetClient();
    
  6. Inviare la richiesta al servizio Web. Verificare l'esito dell'operazione dopo la restituzione del risultato.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    
  7. Compilare ed eseguire l'app. Selezionare una parte dall'elenco e quindi selezionare Elimina nella pagina Aggiungi parte . Se l'operazione ha esito positivo, la pagina Part List viene visualizzata nuovamente e il componente eliminato non è più visibile.