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

SI APPLICA A: NoSQL

Azure SDK per .NET consente di eseguire query sui dati in un contenitore API per NoSQL usando LINQ in C# o una stringa di query SQL. Questa esercitazione illustra in dettaglio il processo di aggiornamento di un'applicazione Web ASP.NET esistente che usa i dati segnaposto per eseguire query dall'API.

In questa esercitazione apprenderai a:

  • Creare e popolare un database e un contenitore usando l'API per NoSQL
  • Creare un'applicazione Web ASP.NET da un modello
  • Eseguire query sui dati dal contenitore API per NoSQL usando Azure SDK per .NET

Prerequisiti

Creare un'API per le risorse NoSQL

Prima di tutto, si creerà un database e un contenitore nell'account API esistente per NoSQL. Questo account verrà quindi popolato con i dati usando lo cosmicworks strumento dotnet.

  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 del campo PRIMARY CONNECTION STRING*. Questo valore verrà usato in tutta l'esercitazione.

    Screenshot della pagina Chiavi con i campi URI, Chiave primaria e Stringa di Connessione 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 contenitore nella barra dei comandi.

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

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

    Impostazione Valore
    ID database cosmicworks
    Tipo di velocità effettiva del database Manualee
    Quantità di velocità effettiva del database 1000
    ID contenitore products
    Chiave di partizione /category/name

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

    Importante

    In questa esercitazione verrà prima ridimensionato il database fino a 1.000 UR/sec in velocità effettiva condivisa per ottimizzare le prestazioni per la migrazione dei dati. Al termine della migrazione dei dati, si passerà a 400 UR/sec di velocità effettiva con provisioning.

  7. Selezionare OK per creare il database e il contenitore.

  8. Aprire un terminale per eseguire i comandi per popolare il contenitore con i dati.

    Suggerimento

    Facoltativamente, è possibile usare Azure Cloud Shell qui.

  9. Installare v2 dello cosmicworks strumento dotnet da NuGet.

    dotnet tool install --global cosmicworks  --version 2.*
    
  10. Usare lo strumento per popolare l'account cosmicworks API per NoSQL con i dati di prodotto di esempio usando i valori URI e CHIAVE PRIMARIA registrati in precedenza in questo lab. Questi valori registrati verranno usati rispettivamente per i endpoint parametri e key .

    cosmicworks \
        --number-of-products 1759 \
        --number-of-employees 0 \
        --disable-hierarchical-partition-keys \
        --connection-string <nosql-connection-string>
    
  11. Osservare l'output dello strumento da riga di comando. Deve aggiungere 1759 elementi al contenitore. L'output di esempio incluso viene troncato per brevità.

    ── Parsing connection string ────────────────────────────────────────────────────────────────
    ╭─Connection string──────────────────────────────────────────────────────────────────────────╮
    │ AccountEndpoint=https://<account-name>.documents.azure.com:443/;AccountKey=<account-key>;  │
    ╰────────────────────────────────────────────────────────────────────────────────────────────╯
    ── Populating data ──────────────────────────────────────────────────────────────────────────
    ╭─Products configuration─────────────────────────────────────────────────────────────────────╮
    │ Database   cosmicworks                                                                     │
    │ Container  products                                                                        │
    │ Count      1,759                                                                           │
    ╰────────────────────────────────────────────────────────────────────────────────────────────╯
    ...
    [SEED]  00000000-0000-0000-0000-000000005951 | Road-650 Black, 60 - Bikes
    [SEED]  00000000-0000-0000-0000-000000005950 | Mountain-100 Silver, 42 - Bikes
    [SEED]  00000000-0000-0000-0000-000000005949 | Men's Bib-Shorts, L - Clothing
    [SEED]  00000000-0000-0000-0000-000000005948 | ML Mountain Front Wheel - Components
    [SEED]  00000000-0000-0000-0000-000000005947 | Mountain-500 Silver, 42 - Bikes
    
  12. Tornare alla pagina Esplora dati per l'account.

  13. Nella sezione Dati espandere il nodo del cosmicworks database e quindi selezionare Ridimensiona.

    Screenshot dell'opzione Ridimensiona all'interno del nodo del database.

  14. Ridurre la velocità effettiva da 1.000 a 400.

    Screenshot delle impostazioni di velocità effettiva per il database ridotto a 400 UR/sec.

  15. Sulla barra dei comandi selezionare Salva.

    Screenshot dell'opzione Salva nella barra dei comandi Esplora dati.

  16. Nella sezione Dati espandere e selezionare il nodo contenitore products.

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

  17. Nella barra dei comandi selezionare Nuova query SQL.

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

  18. Nell'editor di query aggiungere questa stringa di query SQL.

    SELECT
      p.sku,
      p.price
    FROM products p
    WHERE p.price < 2000
    ORDER BY p.price DESC
    
  19. Selezionare Esegui query per eseguire la query e osservare i risultati.

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

  20. I risultati devono essere una matrice impaginata di tutti gli elementi nel contenitore con un price valore minore di 2.000 ordinati dal prezzo più alto al più basso. Per brevità, qui è incluso un subset dell'output.

    [
      {
        "sku": "BK-R79Y-48",
        "price": 1700.99
      },
      ...
      {
        "sku": "FR-M94B-46",
        "price": 1349.6
      },
    ...
    
  21. Sostituire il contenuto dell'editor di query con questa query e quindi selezionare di nuovo Esegui query per osservare i risultati.

    SELECT
        p.name,
        p.category.name AS category,
        p.category.subCategory.name AS subcategory,
        p.tags
    FROM products p
    JOIN tag IN p.tags
    WHERE STRINGEQUALS(tag, "yellow", true)
    
  22. I risultati devono essere una matrice più piccola di elementi filtrati per contenere solo elementi che includono almeno un tag con un valore name di Tag-32. Anche in questo caso, per brevità viene incluso un subset dell'output.

    [
      ...
      {
        "name": "HL Touring Frame - Yellow, 60",
        "category": "Components",
        "subcategory": "Touring Frames",
        "tags": [
          "Components",
          "Touring Frames",
          "Yellow",
          "60"
        ]
      },
      ...
    ]
    

Creare un'applicazione Web ASP.NET

A questo punto si creerà una nuova applicazione Web ASP.NET usando un modello di progetto di esempio. Si esaminerà quindi il codice sorgente ed si eseguirà l'esempio per acquisire familiarità con l'applicazione prima di aggiungere la connettività di Azure Cosmos DB usando Azure SDK per .NET.

Importante

Questa esercitazione esegue il pull trasparente dei pacchetti da NuGet. È possibile usare dotnet nuget list source per verificare le origini dei pacchetti. Se NuGet non è un'origine del pacchetto, usare dotnet nuget add source per installare il sito come origine.

  1. Aprire un terminale in una directory vuota.

  2. Installare il pacchetto del modello di cosmicworks.template.web progetto da NuGet.

    dotnet new install cosmicworks.template.web
    
  3. Creare un nuovo progetto di applicazione Web usando il modello appena installato dotnet new cosmosdbnosql-webapp .

    dotnet new cosmosdbnosql-webapp
    
  4. Compilare ed eseguire il progetto dell'applicazione Web.

    dotnet run
    
  5. Osservare l'output del comando run. L'output deve includere un elenco di porte e URL in cui è in esecuzione l'applicazione.

    ...
    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: http://localhost:5000
    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: https://localhost:5001
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    info: Microsoft.Hosting.Lifetime[0]
          Hosting environment: Production
    ...
    
  6. Aprire un nuovo browser e passare all'applicazione Web in esecuzione. Osservare tutte e tre le pagine dell'applicazione in esecuzione.

    Screenshot dell'applicazione Web di esempio in esecuzione con i dati segnaposto.

  7. Arrestare l'applicazione in esecuzione terminando il processo in esecuzione.

    Suggerimento

    Usare il comando CTRL+C per arrestare un processo in esecuzione. In alternativa, è possibile chiudere e riaprire il terminale.

  8. 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.

  9. Passare a e aprire il file Servizi/ICosmosService.cs . Osservare le implementazioni del RetrieveActiveProductsAsync metodo e RetrieveAllProductsAsync predefinite. Questi metodi creano un elenco statico di prodotti da usare quando si esegue il progetto per la prima volta. Di seguito è riportato un esempio troncato di uno dei metodi.

    public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync()
    {
        await Task.Delay(1);
    
        return new List<Product>()
        {
            new Product(id: "baaa4d2d-5ebe-45fb-9a5c-d06876f408e0", category: new Category(name: "Components, Road Frames"), sku: "FR-R72R-60", name: """ML Road Frame - Red, 60""", description: """The product called "ML Road Frame - Red, 60".""", price: 594.83000000000004m),
            new Product(id: "bd43543e-024c-4cda-a852-e29202310214", category: new Category(name: "Components, Forks"), sku: "FK-5136", name: """ML Fork""", description: """The product called "ML Fork".""", price: 175.49000000000001m),
            ...
        };
    }
    
  10. Passare a e aprire il file Servizi/CosmosService.cs . Osservare l'implementazione corrente della classe CosmosService . Questa classe implementa l'interfaccia ICosmosService , ma non esegue l'override di alcun metodo. In questo contesto, la classe userà l'implementazione dell'interfaccia predefinita fino a quando non viene fornito un override dell'implementazione nell'interfaccia .

    public class CosmosService : ICosmosService
    { }
    
  11. Infine, passare a e aprire i file Models/Product.cs e Models/Category.cs . Osservare i tipi di record definiti in ogni file. Questi tipi verranno usati nelle query in questa esercitazione.

    public record Product(
        string id,
        Category category,
        string sku,
        string name,
        string description,
        decimal price
    );
    
    public record Category(
        string name
    );
    

Eseguire query sui dati con .NET SDK

Si aggiungerà quindi Azure SDK per .NET a questo progetto di esempio e si userà la libreria per eseguire query sui dati dal contenitore API per NoSQL.

  1. Tornare al terminale, aggiungere il Microsoft.Azure.Cosmos pacchetto da NuGet.

    dotnet add package Microsoft.Azure.Cosmos
    
  2. Compilare il progetto.

    dotnet build
    
  3. Tornare a Visual Studio Code e passare di nuovo al file Servizi/CosmosService.cs .

  4. Aggiungere una nuova direttiva using per gli spazi dei Microsoft.Azure.Cosmos nomi e Microsoft.Azure.Cosmos.Linq .

    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    
  5. All'interno della classe CosmosService aggiungere un nuovo private readonly membro di tipo CosmosClient denominato _client.

    private readonly CosmosClient _client;
    
  6. Creare un nuovo costruttore vuoto per la CosmosService classe .

    public CosmosService()
    { }
    
  7. All'interno del costruttore creare una nuova istanza della CosmosClient classe passando un parametro stringa con il valore PRIMARY CONNECTION STRING registrato in precedenza nel lab. Archiviare questa nuova istanza nel _client membro.

    public CosmosService()
    { 
        _client = new CosmosClient(
            connectionString: "<primary-connection-string>"
        );
    }
    
  8. Tornare all'interno della classe CosmosService , creare una nuova private proprietà di tipo Container denominata container. Impostare la funzione di accesso get per restituire il database e products il cosmicworks contenitore.

    private Container container
    {
        get => _client.GetDatabase("cosmicworks").GetContainer("products");
    }
    
  9. Creare un nuovo metodo asincrono denominato RetrieveAllProductsAsync che restituisce un oggetto IEnumerable<Product>.

    public async Task<IEnumerable<Product>> RetrieveAllProductsAsync()
    { }
    
  10. Per i passaggi successivi, aggiungere questo codice all'interno del RetrieveAllProductsAsync metodo .

    1. Usare il GetItemLinqQueryable<> metodo generico per ottenere un oggetto di tipo IQueryable<> che è possibile usare per costruire una query integrata nel linguaggio (LINQ). Archiviare l'oggetto in una variabile denominata queryable.

      var queryable = container.GetItemLinqQueryable<Product>();
      
    2. Creare una query LINQ usando i Where metodi di estensione e OrderByDescending . Usare il ToFeedIterator metodo di estensione per creare un iteratore per ottenere dati da Azure Cosmos DB e 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 FeedIterator<Product> feed = queryable
          .Where(p => p.price < 2000m)
          .OrderByDescending(p => p.price)
          .ToFeedIterator();
      
    3. Creare una nuova variabile denominata results usando il tipo generico List<> .

      List<Product> results = new();
      
    4. Creare un ciclo while che scorrerà fino a quando la HasMoreResults proprietà della feed variabile restituisce false. Questo ciclo garantisce il ciclo di tutte le pagine dei risultati lato server.

      while (feed.HasMoreResults)
      { }
      
    5. All'interno del ciclo while chiamare in modo asincrono il ReadNextAsync metodo della feed variabile e archiviare il risultato in una variabile denominata response.

      while (feed.HasMoreResults)
      {
          var response = await feed.ReadNextAsync();
      }
      
    6. Sempre all'interno del ciclo while, usare un ciclo foreach per scorrere ogni elemento nella risposta e aggiungerli all'elencoresults.

      while (feed.HasMoreResults)
      {
          var response = await feed.ReadNextAsync();
          foreach (Product item in response)
          {
              results.Add(item);
          }
      }
      
    7. Restituisce l'elenco results come output del RetrieveAllProductsAsync metodo .

      return results;
      
  11. Creare un nuovo metodo asincrono denominato RetrieveActiveProductsAsync che restituisce un oggetto IEnumerable<Product>.

    public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync()
    { }
    
  12. Per i passaggi successivi, aggiungere questo codice all'interno del RetrieveActiveProductsAsync metodo .

    1. Creare una nuova stringa denominata sql con una query SQL per recuperare più campi in cui viene applicato un filtro (@tagFilter) alla matrice di tag di ogni elemento.

      string sql = """
      SELECT
          p.id,
          p.name,
          p.category,
          p.sku,
          p.description,
          p.price
      FROM products p
      JOIN tag IN p.tags
      WHERE STRINGEQUALS(tag, @tagFilter, true)
      """;
      
    2. Creare una nuova QueryDefinition variabile denominata query passando la sql stringa come unico parametro di query. Usare anche il WithParameter metodo fluido per applicare il valore red al @tagFilter parametro .

      var query = new QueryDefinition(
          query: sql
      )
          .WithParameter("@tagFilter", "red");
      
    3. Usare il GetItemQueryIterator<> metodo generico e la query variabile per creare un iteratore che ottiene i 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 FeedIterator<Product> feed = container.GetItemQueryIterator<Product>(
          queryDefinition: query
      );
      
    4. Usare un ciclo while per scorrere più pagine di risultati e archiviare il valore in un risultato denominato genericoList<>. Restituisce i risultati come output del RetrieveActiveProductsAsync metodo .

      List<Product> results = new();
      
      while (feed.HasMoreResults)
      {
          FeedResponse<Product> response = await feed.ReadNextAsync();
          foreach (Product item in response)
          {
              results.Add(item);
          }
      }
      
      return results;
      
  13. Salvare il file Servizi/CosmosClient.cs .

    Suggerimento

    Se non si è certi che il codice sia corretto, è possibile controllare il codice sorgente rispetto al codice di esempio in GitHub.

Convalidare l'applicazione finale

Infine, si eseguirà l'applicazione con ricaricamenti ad accesso frequente abilitati. L'esecuzione dell'applicazione convaliderà che il codice possa accedere ai dati dall'API per NoSQL.

  1. Tornare al terminale ed eseguire l'applicazione.

    dotnet run
    
  2. L'output del comando di esecuzione deve includere un elenco di porte e URL in cui è in esecuzione l'applicazione. Aprire un nuovo browser e passare all'applicazione Web in esecuzione. Osservare tutte e tre le pagine dell'applicazione in esecuzione. Ogni pagina dovrebbe ora includere dati in tempo reale da Azure Cosmos DB.

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 cosmicworks database e quindi selezionare Elimina.

Passaggi successivi

Dopo aver creato la prima applicazione Web .NET con Azure Cosmos DB, è ora possibile approfondire l'SDK per importare più dati, eseguire query complesse e gestire le risorse di Azure Cosmos DB per NoSQL.