Condividi tramite


Esercitazione: Sviluppare un'applicazione console .NET con Azure Cosmos DB per NoSQL

SI APPLICA A: NoSQL

Azure SDK per .NET consente di aggiungere dati a un contenitore API per NoSQL sia con singole operazioni asincrone che con un batch transazionale. Questa esercitazione illustra il processo di creazione di una nuova applicazione console .NET che aggiunge più elementi a un contenitore.

In questa esercitazione apprenderai a:

  • Creare un database usando l'API per NoSQL
  • Creare un'applicazione console .NET e aggiungere Azure SDK per .NET
  • Aggiungere singoli elementi in un contenitore API per NoSQL
  • Recuperare elementi efficienti da un contenitore API per NoSQL
  • Creare una transazione con modifiche batch per il contenitore API per NoSQL

Prerequisiti

Creare un'API per le risorse NoSQL

Creare prima di tutto un database vuoto nell'account API esistente per NoSQL. Si crea un contenitore usando Azure SDK per .NET in un secondo momento.

  1. Passare all'account API esistente per NoSQL nel portale di Azure.

  2. Nel menu della risorsa selezionare Chiavi.

    Screenshot di una pagina dell'account API per NoSQL. L'opzione Chiavi è evidenziata nel menu della risorsa.

  3. Nella pagina Chiavi osservare e registrare il valore dei campi URI e CHIAVE PRIMARIA. Questi valori vengono usati in tutta l'esercitazione.

    Screenshot della pagina Chiavi con i campi URI e Chiave primaria evidenziati.

  4. Nel menu della risorsa selezionare Esplora dati.

    Screenshot dell'opzione Esplora dati evidenziata nel menu delle risorse.

  5. Nella pagina Esplora dati selezionare l'opzione Nuovo database nella barra dei comandi.

    Screenshot dell'opzione Nuovo database nella barra dei comandi Esplora dati.

  6. Nella finestra di dialogo Nuovo database creare un nuovo contenitore con le impostazioni seguenti:

    Valore
    ID database cosmicworks
    Tipo di velocità effettiva del database Manualee
    Quantità di velocità effettiva del database 400

    Screenshot della finestra di dialogo Nuovo database nella Esplora dati con vari valori in ogni campo.

  7. Selezionare OK per creare il database.

Creare un'applicazione console .NET

A questo punto, si crea una nuova applicazione console .NET e si importa Azure SDK per .NET usando la Microsoft.Azure.Cosmos libreria da NuGet.

  1. Aprire un terminale in una directory vuota.

  2. Creare una nuova applicazione console usando il modello predefinito console

    dotnet new console --langVersion preview
    
  3. Aggiungere la versione 3.31.1-preview del pacchetto Microsoft.Azure.Cosmos da NuGet.

    dotnet add package Microsoft.Azure.Cosmos --version 3.31.1-preview
    
  4. Aggiungere anche la versione non definitiva del pacchetto System.CommandLine da NuGet.

    dotnet add package System.CommandLine --prerelease
    
  5. Aggiungere anche il pacchetto Humanizer da NuGet.

    dotnet add package Humanizer
    
  6. Compilare il progetto dell'applicazione console.

    dotnet build
    
  7. Aprire Visual Studio Code usando la cartella del progetto corrente come area di lavoro.

    Suggerimento

    È possibile eseguire code . nel terminale per aprire Visual Studio Code e aprire automaticamente la directory di lavoro come area di lavoro corrente.

  8. Passare a e aprire il file Program.cs. Eliminare tutto il codice esistente nel file.

  9. Aggiungere questo codice al file per usare la libreria System.CommandLine per analizzare la riga di comando per due stringhe passate tramite le opzioni --first e --last.

    using System.CommandLine;
    
    var command = new RootCommand();
    
    var nameOption = new Option<string>("--name") { IsRequired = true };
    var emailOption = new Option<string>("--email");
    var stateOption = new Option<string>("--state") { IsRequired = true };
    var countryOption = new Option<string>("--country") { IsRequired = true };
    
    command.AddOption(nameOption);
    command.AddOption(emailOption);
    command.AddOption(stateOption);
    command.AddOption(countryOption);
    
    command.SetHandler(
        handle: CosmosHandler.ManageCustomerAsync, 
        nameOption, 
        emailOption,
        stateOption,
        countryOption
    );
    
    await command.InvokeAsync(args);
    

    Nota

    Per questa esercitazione, non è del tutto importante comprendere il funzionamento del parser della riga di comando. Il parser dispone di quattro opzioni che possono essere specificate quando l'applicazione è in esecuzione. Sono necessarie tre delle opzioni perché verranno usate per costruire i campi ID e chiave di partizione.

  10. A questo punto, il progetto non verrà compilato perché non è ancora stato definito il metodo CosmosHandler.ManageCustomerAsync statico.

  11. Salvare il file Program.cs.

Aggiungere elementi a un contenitore usando l'SDK

Successivamente, si usano singole operazioni per aggiungere elementi al contenitore API per NoSQL. In questa sezione viene definito il CosmosHandler.ManageCustomerAsync metodo .

  1. Creare un nuovo file CosmosHandler.cs.

  2. Nel file CosmosHandler.cs aggiungere una nuova direttiva using per gli spazi dei nomi Humanizer e Microsoft.Azure.Cosmos.

    using Humanizer;
    using Microsoft.Azure.Cosmos;
    
  3. Creare una nuova classe statica denominata CosmosHandler.

    public static class CosmosHandler
    { }
    
  4. Per convalidare il funzionamento di questa app, creare una breve implementazione del metodo statico ManageCustomerAsync per stampare l'input della riga di comando.

    public static async Task ManageCustomerAsync(string name, string email, string state, string country)
    {
        await Console.Out.WriteLineAsync($"Hello {name} of {state}, {country}!");
    }
    
  5. Salvare il file CosmosHandler.cs.

  6. Tornare al terminale ed eseguire l'applicazione.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  7. L'output del comando deve essere un messaggio di saluto divertente.

    Hello Mica Pereira of Washington, United States!
    
  8. Tornare al file CosmosHandler.cs.

  9. All'interno della classe CosmosHandler statica, aggiungere un nuovo membro private static readonly di tipo CosmosClient denominato _client.

    private static readonly CosmosClient _client;
    
  10. Creare un nuovo costruttore statico per la classe CosmosHandler.

    static CosmosHandler()
    { }
    
  11. All'interno del costruttore creare una nuova istanza della classe CosmosClient passando due parametri stringa con i valori URI e PRIMARY KEY registrati in precedenza nel lab. Archiviare questa nuova istanza nel membro _client.

    static CosmosHandler()
    {
        _client = new CosmosClient(
            accountEndpoint: "<uri>", 
            authKeyOrResourceToken: "<primary-key>"
        );
    }
    
  12. Tornare all'interno della classe CosmosHandler statica, creare un nuovo metodo asincrono denominato GetContainerAsync che restituisce un oggetto Container.

    private static async Task<Container> GetContainerAsync()
    { }
    
  13. Per i passaggi successivi, aggiungere questo codice all'interno del metodo GetContainerAsync.

    1. Ottenere il database cosmicworks e archiviarlo in una variabile denominata database.

      Database database = _client.GetDatabase("cosmicworks");
      
    2. Creare una nuova List<> generica di valori string all'interno di un elenco di percorsi di chiave di partizione gerarchici e archiviarla in una variabile denominata keyPaths.

      List<string> keyPaths = new()
      {
          "/address/country",
          "/address/state"
      };
      
    3. Creare una nuova variabile ContainerProperties con il nome del contenitore (customers) e l'elenco dei percorsi delle chiavi di partizione.

      ContainerProperties properties = new(
          id: "customers",
          partitionKeyPaths: keyPaths
      );
      
    4. Usare il metodo CreateContainerIfNotExistsAsync per fornire le proprietà del contenitore e recuperare il contenitore. Questo metodo, come dice il nome, creerà in modo asincrono il contenitore se non esiste già all'interno del database. Restituisce il risultato come output del metodo GetContainerAsync.

      return await database.CreateContainerIfNotExistsAsync(
          containerProperties: properties
      );
      
  14. Eliminare tutto il codice all'interno del metodo ManageCustomerAsync.

  15. Per i passaggi successivi, aggiungere questo codice all'interno del metodo ManageCustomerAsync.

    1. Chiamare in modo asincrono il metodo GetContainerAsync e archiviare il risultato in una variabile denominata container.

      Container container = await GetContainerAsync();
      
    2. Creare una nuova variabile denominata id che usa il metodo Kebaberize da Humanizer per trasformare il parametro del metodo name.

      string id = name.Kebaberize();
      

      Nota

      Il metodo Kebaberize sostituirà tutti gli spazi con trattini e convertirà il testo in minuscolo.

    3. Creare un nuovo elemento tipizzato anonimo usando i parametri del metodo name, state e country e la variabile id. Archiviare l'elemento come variabile denominata customer.

      var customer = new {
          id = id,
          name = name,
          address = new {
              state = state,
              country = country
          }
      };
      
    4. Usare il metodo CreateItemAsync asincrono del contenitore per creare un nuovo elemento nel contenitore e assegnare i metadati della risposta HTTP a una variabile denominata response.

      var response = await container.CreateItemAsync(customer);
      
    5. Scrivere i valori delle proprietà StatusCode e RequestCharge della variabile di response nella console. Scrivere anche il valore della variabile id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
      
  16. Salvare il file CosmosHandler.cs.

  17. Tornare al terminale, eseguire di nuovo l'applicazione.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  18. L'output del comando deve includere uno stato e un addebito per la richiesta per l'operazione.

    [Created]       mica-pereira    7.05 RUs
    

    Nota

    L'addebito della richiesta può variare.

  19. Eseguire l'applicazione ancora una volta.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  20. Questa volta, il programma dovrebbe arrestarsi in modo anomalo. Se si scorre il messaggio di errore, viene visualizzato l'arresto anomalo a causa di un conflitto nell'identificatore univoco per gli elementi.

    Unhandled exception: Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: Conflict (409);Reason: (
        Errors : [
          "Resource with specified id or name already exists."
        ]
    );
    

Recuperare un elemento usando l'SDK

Dopo aver creato il primo elemento nel contenitore, è possibile usare lo stesso SDK per recuperare l'elemento. In questo caso, si eseguirà una query e si leggerà l'elemento per confrontare la differenza nel consumo di unità richiesta (UR).

  1. Tornare o aprire il file CosmosHandler.cs.

  2. Eliminare tutte le righe di codice dal metodo ManageCustomerAsync ad eccezione delle prime due righe.

    public static async Task ManageCustomerAsync(string name, string email, string state, string country)
    {
        Container container = await GetContainerAsync();
    
        string id = name.Kebaberize();
    }
    
  3. Per i passaggi successivi, aggiungere questo codice all'interno del metodo ManageCustomerAsync.

    1. Usare il metodo CreateItemAsync asincrono del contenitore per creare un nuovo elemento nel contenitore e assegnare i metadati della risposta HTTP a una variabile denominata response.

      var response = await container.CreateItemAsync(customer);
      
    2. Creare una nuova stringa denominata sql con una query SQL per recuperare gli elementi in cui corrisponde un filtro (@id).

      string sql = @"
      SELECT
          *
      FROM customers c
      WHERE c.id = @id
      ";
      
    3. Creare una nuova variabile di QueryDefinition denominata query passando la stringa sql come unico parametro di query. Usare inoltre il metodo fluido WithParameter per applicare il valore della variabile id al parametro @id.

      var query = new QueryDefinition(
          query: sql
      )
          .WithParameter("@id", id);
      
    4. Usare il metodo generico GetItemQueryIterator<> e la variabile query per creare un iteratore che ottiene dati da Azure Cosmos DB. Archiviare l'iteratore in una variabile denominata feed. Eseguire il wrapping di questa intera espressione in un'istruzione using per eliminare l'iteratore in un secondo momento.

      using var feed = container.GetItemQueryIterator<dynamic>(
          queryDefinition: query
      );
      
    5. Chiamare in modo asincrono il metodo ReadNextAsync della variabile feed e archiviare il risultato in una variabile denominata response.

      var response = await feed.ReadNextAsync();
      
    6. Scrivere i valori delle proprietà StatusCode e RequestCharge della variabile di response nella console. Scrivere anche il valore della variabile id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
      
  4. Salvare il file CosmosHandler.cs.

  5. Tornando al terminale, eseguire l'applicazione per leggere il singolo elemento usando una query SQL.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  6. L'output del comando deve indicare che la query richiede più unità richiesta (UR).

    [OK]    mica-pereira    2.82 RUs
    
  7. Tornare al file CosmosHandler.cs, eliminare di nuovo tutte le righe di codice dal metodo ManageCustomerAsync ad eccezione delle prime due righe.

    public static async Task ManageCustomerAsync(string name, string email, string state, string country)
    {
        Container container = await GetContainerAsync();
    
        string id = name.Kebaberize();
    }
    
  8. Per i passaggi successivi, aggiungere questo codice all'interno del metodo ManageCustomerAsync.

    1. Creare una nuova istanza di PartitionKeyBuilder aggiungendo i parametri state e country come valore della chiave di partizione in più parti.

      var partitionKey = new PartitionKeyBuilder()
          .Add(country)
          .Add(state)
          .Build();
      
    2. Usare il metodo ReadItemAsync<> del contenitore per puntare a leggere l'elemento dal contenitore usando le variabili id e partitionKey. Salvare il risultato in una variabile denominata response.

      var response = await container.ReadItemAsync<dynamic>(
          id: id, 
          partitionKey: partitionKey
      );
      
    3. Scrivere i valori delle proprietà StatusCode e RequestCharge della variabile di response nella console. Scrivere anche il valore della variabile id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RU");
      
  9. Salvare di nuovo il file CosmosHandler.cs.

  10. Tornare al terminale, eseguire l'applicazione ancora una volta per puntare a leggere il singolo elemento.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  11. L'output del comando deve indicare che la query richiede una singola UR.

    [OK]    mica-pereira    1 RUs
    

Creare una transazione usando l'SDK

Infine, si prende l'elemento creato, si legge tale elemento e si crea un elemento correlato diverso come parte di una singola transazione usando Azure SDK per .NET.

  1. Tornare o aprire il file CosmosHandler.cs.

  2. Eliminare queste righe di codice dal metodo ManageCustomerAsync.

    var response = await container.ReadItemAsync<dynamic>(
        id: id, 
        partitionKey: partitionKey
    );
    
    Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
    
  3. Per i passaggi successivi, aggiungere questo nuovo codice all'interno del metodo ManageCustomerAsync.

    1. Creare un nuovo elemento tipizzato anonimo usando i parametri del metodo name, state e country e la variabile id. Archiviare l'elemento come variabile denominata customerCart. Questo articolo rappresenta un carrello acquisti in tempo reale per il cliente attualmente vuoto.

      var customerCart = new {
          id = $"{Guid.NewGuid()}",
          customerId = id,
          items = new string[] {},
          address = new {
              state = state,
              country = country
          }
      };
      
    2. Creare un altro nuovo elemento tipizzato anonimo usando i parametri del metodo name, state e country e la variabile id. Archiviare l'elemento come variabile denominata customerCart. Questo articolo rappresenta le informazioni di spedizione e contatto per il cliente.

      var customerContactInfo = new {
          id = $"{id}-contact",
          customerId = id,
          email = email,
          location = $"{state}, {country}",
          address = new {
              state = state,
              country = country
          }
      };
      
    3. Creare un nuovo batch usando il metodo CreateTransactionalBatch del contenitore passando la variabile partitionKey. Archiviare il batch in una variabile denominata batch. Usare i metodi Fluent per eseguire le azioni seguenti:

      metodo Parametro
      ReadItem id variabile stringa
      CreateItem customerCart variabile di tipo anonimo
      CreateItem customerContactInfo variabile di tipo anonimo
      var batch = container.CreateTransactionalBatch(partitionKey)
          .ReadItem(id)
          .CreateItem(customerCart)
          .CreateItem(customerContactInfo);
      
    4. Usare il metodo ExecuteAsync del batch per avviare la transazione. Salvare il risultato in una variabile denominata response.

      using var response = await batch.ExecuteAsync();
      
    5. Scrivere i valori delle proprietà StatusCode e RequestCharge della variabile di response nella console. Scrivere anche il valore della variabile id.

      Console.WriteLine($"[{response.StatusCode}]\t{response.RequestCharge} RUs");
      
  4. Salvare di nuovo il file CosmosHandler.cs.

  5. Tornare al terminale, eseguire l'applicazione ancora una volta per puntare a leggere il singolo elemento.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  6. L'output del comando deve mostrare le unità richiesta usate per l'intera transazione.

    [OK]    16.05 RUs
    

    Nota

    L'addebito della richiesta può variare.

Convalidare i dati finali in Esplora dati

Per riepilogare gli elementi, usare il Esplora dati nella portale di Azure per visualizzare i dati e il contenitore creati in questa esercitazione.

  1. Passare all'account API esistente per NoSQL nel portale di Azure.

  2. Nel menu della risorsa selezionare Esplora dati.

    Screenshot dell'opzione Esplora dati evidenziata nel menu delle risorse.

  3. Nella pagina Esplora dati espandere il database cosmicworks e quindi selezionare il contenitore customers.

    Screenshot del nodo contenitore selezionato all'interno del nodo del database.

  4. Nella barra dei comandi selezionare Nuova query SQL.

    Screenshot dell'opzione Nuova query SQL nella barra dei comandi Esplora dati.

  5. Nell'editor di query osservare questa stringa di query SQL.

    SELECT * FROM c
    
  6. Selezionare Esegui query per eseguire la query e osservare i risultati.

    Screenshot dell'opzione

  7. I risultati devono includere una matrice JSON con tre elementi creati in questa esercitazione. Si noti che tutti gli elementi hanno lo stesso valore di chiave di partizione gerarchica, ma campi ID univoci. L'output di esempio incluso viene troncato per brevità.

    [
      {
        "id": "mica-pereira",
        "name": "Mica Pereira",
        "address": {
          "state": "Washington",
          "country": "United States"
        },
        ...
      },
      {
        "id": "33d03318-6302-4559-b5c0-f3cc643b2f38",
        "customerId": "mica-pereira",
        "items": [],
        "address": {
          "state": "Washington",
          "country": "United States"
        },
        ...
      },
      {
        "id": "mica-pereira-contact",
        "customerId": "mica-pereira",
        "email": null,
        "location": "Washington, United States",
        "address": {
          "state": "Washington",
          "country": "United States"
        },
        ...
      }
    ]
    

Pulire le risorse

Quando non è più necessario, eliminare il database usato in questa esercitazione. A tale scopo, passare alla pagina account, selezionare Esplora dati, selezionare il database cosmicworks e quindi selezionare Elimina.