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
- Un account Azure Cosmos DB for NoSQL già presente.
- Se si ha già una sottoscrizione di Azure, creare un nuovo account.
- Se non si ha una sottoscrizione di Azure, è possibile provare Azure Cosmos DB gratuitamente senza necessità di carta di credito.
- Visual Studio Code
- .NET 6 (LTS) o versioni successive
- Esperienza nella scrittura di applicazioni C#.
Creare un'API per le risorse NoSQL
Prima di tutto, si creeranno un database e un contenitore nell'account API esistente per NoSQL. Questo account verrà quindi popolato con i dati usando lo strumento dotnet cosmicworks
.
Passare all'account API esistente per NoSQL nel portale di Azure.
Nel menu della risorsa selezionare Chiavi.
Nella pagina Chiavi osservare e registrare il valore del campo PRIMARY CONNECTION STRING*. Questo valore verrà usato in tutta l'esercitazione.
Nel menu della risorsa selezionare Esplora dati.
Nella pagina Esplora dati selezionare l'opzione Nuovo contenitore nella barra dei comandi.
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
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.
Selezionare OK per creare il database e il contenitore.
Aprire un terminale per eseguire i comandi per popolare il contenitore con i dati.
Suggerimento
È anche possibile usare Azure Cloud Shell qui.
Installare v2 dello
cosmicworks
strumento dotnet da NuGet.dotnet tool install --global cosmicworks --version 2.*
Usare lo strumento
cosmicworks
per popolare l'account API per NoSQL con i dati di prodotto di esempio usando l’URI e i valori CHIAVE PRIMARIA registrati in precedenza in questo lab. Questi valori registrati verranno usati rispettivamente per i parametriendpoint
ekey
.cosmicworks \ --number-of-products 1759 \ --number-of-employees 0 \ --disable-hierarchical-partition-keys \ --connection-string <nosql-connection-string>
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
Tornare alla pagina Esplora dati per l'account.
Nella sezione Dati espandere il nodo del database
cosmicworks
e quindi selezionare Ridimensiona.Ridurre la velocità effettiva da 1.000 a 400.
Sulla barra dei comandi selezionare Salva.
Nella sezione Dati espandere e selezionare il nodo del contenitore prodotti.
Nella barra dei comandi selezionare Nuova query SQL.
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
Selezionare Esegui query per eseguire la query e osservare i risultati.
I risultati devono essere una matrice impaginata di tutti gli elementi nel contenitore con un valore
price
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 }, ...
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)
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.
Aprire un terminale in una directory vuota.
Installare il pacchetto modello di progetto
cosmicworks.template.web
da NuGet.dotnet new install cosmicworks.template.web
Creare un nuovo progetto di applicazione Web usando il modello
dotnet new cosmosdbnosql-webapp
appena installato.dotnet new cosmosdbnosql-webapp
Compilare ed eseguire il progetto dell'applicazione Web.
dotnet run
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 ...
Aprire un nuovo browser e passare all'applicazione Web in esecuzione. Osservare tutte e tre le pagine dell'applicazione in esecuzione.
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.
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.Passare a e aprire il file Services/ICosmosService.cs. Osservare le implementazioni del metodo
RetrieveActiveProductsAsync
eRetrieveAllProductsAsync
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), ... }; }
Passare a e aprire il file Services/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 { }
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.
Tornare al terminale, aggiungere il pacchetto
Microsoft.Azure.Cosmos
da NuGet.dotnet add package Microsoft.Azure.Cosmos
Compilare il progetto.
dotnet build
Tornare a Visual Studio Code e passare di nuovo al file Services/CosmosService.cs.
Aggiungere una nuova direttiva using per gli spazi dei nomi
Microsoft.Azure.Cosmos
eMicrosoft.Azure.Cosmos.Linq
.using Microsoft.Azure.Cosmos; using Microsoft.Azure.Cosmos.Linq;
All'interno della classe CosmosService aggiungere un nuovo membro
private readonly
di tipoCosmosClient
denominato_client
.private readonly CosmosClient _client;
Creare un nuovo costruttore vuoto per la classe
CosmosService
.public CosmosService() { }
All'interno del costruttore creare una nuova istanza della classe
CosmosClient
passando un parametro stringa con il valore PRIMARY CONNECTION STRING precedentemente registrato nel lab. Archiviare questa nuova istanza nel membro_client
.public CosmosService() { _client = new CosmosClient( connectionString: "<primary-connection-string>" ); }
Tornare all'interno della classe CosmosService, creare una nuova proprietà
private
di tipoContainer
denominatacontainer
. Impostare la funzione di accesso get per restituire il databasecosmicworks
e il contenitoreproducts
.private Container container { get => _client.GetDatabase("cosmicworks").GetContainer("products"); }
Creare un nuovo metodo asincrono denominato
RetrieveAllProductsAsync
che restituisce un oggettoIEnumerable<Product>
.public async Task<IEnumerable<Product>> RetrieveAllProductsAsync() { }
Per i passaggi successivi, aggiungere questo codice all'interno del metodo
RetrieveAllProductsAsync
.Usare il metodo generico
GetItemLinqQueryable<>
per ottenere un oggetto di tipoIQueryable<>
che è possibile usare per costruire una query integrata nel linguaggio (LINQ). Archiviare l'oggetto in una variabile denominataqueryable
.var queryable = container.GetItemLinqQueryable<Product>();
Creare una query LINQ usando i metodi di estensione
Where
eOrderByDescending
. Usare il metodo di estensioneToFeedIterator
per creare un iteratore per ottenere dati da Azure Cosmos DB e archiviare l'iteratore in una variabile denominatafeed
. 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();
Creare una nuova variabile denominata
results
usando il tipoList<>
generico.List<Product> results = new();
Creare un ciclo while che scorrerà fino a quando la proprietà
HasMoreResults
della variabilefeed
restituisce false. Questo ciclo garantisce il ciclo di tutte le pagine dei risultati lato server.while (feed.HasMoreResults) { }
All'interno del ciclo while chiamare in modo asincrono il metodo
ReadNextAsync
della variabilefeed
e archiviare il risultato in una variabile denominataresponse
.while (feed.HasMoreResults) { var response = await feed.ReadNextAsync(); }
Sempre all'interno del ciclo while, usare un ciclo foreach per scorrere ogni elemento nella risposta e aggiungerlo all'elenco
results
.while (feed.HasMoreResults) { var response = await feed.ReadNextAsync(); foreach (Product item in response) { results.Add(item); } }
Restituisce l'elenco
results
come output del metodoRetrieveAllProductsAsync
.return results;
Creare un nuovo metodo asincrono denominato
RetrieveActiveProductsAsync
che restituisce un oggettoIEnumerable<Product>
.public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync() { }
Per i passaggi successivi, aggiungere questo codice all'interno del metodo
RetrieveActiveProductsAsync
.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) """;
Creare una nuova variabile di
QueryDefinition
denominataquery
passando la stringasql
come unico parametro di query. Usare inoltre il metodo fluidoWithParameter
per applicare il valorered
al parametro@tagFilter
.var query = new QueryDefinition( query: sql ) .WithParameter("@tagFilter", "red");
Usare il metodo generico
GetItemQueryIterator<>
e la variabilequery
per creare un iteratore che ottiene dati da Azure Cosmos DB. Archiviare l'iteratore in una variabile denominatafeed
. 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 );
Usare un ciclo while per scorrere più pagine di risultati e archiviare il valore in un
List<>
generico denominato risultati. Restituisce i risultati come output del metodoRetrieveActiveProductsAsync
.List<Product> results = new(); while (feed.HasMoreResults) { FeedResponse<Product> response = await feed.ReadNextAsync(); foreach (Product item in response) { results.Add(item); } } return results;
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.
Tornare al terminale ed eseguire l'applicazione.
dotnet run
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 database cosmicworks
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.