Esercizio - Usare i servizi di database per rendere persistenti i dati da un progetto .NET Aspire

Completato

In questo esercizio si sostituiscono gli archivi dati correnti per l'app nativa del cloud in-sviluppo dell'azienda. Al momento, l'app usa un database SQLite archiviato in locale per i dati del catalogo e una cache Redis in memoria per gli acquisti dei clienti. Sostituire gli archivi dati esistenti con PostgreSQL e MongoDB.

Installare i prerequisiti

I prerequisiti per .NET Aspire sono:

  • .NET 8
  • Anteprima di Visual Studio 2022
  • Docker Desktop o Podman
  • Carico di lavoro .NET Aspire in Visual Studio

Se sono già installati i prerequisiti, è possibile procedere alla clonazione dell'app esistente.

Installare .NET 8

Seguire questo collegamento a .NET 8 e selezionare il programma di installazione corretto per il sistema operativo. Ad esempio, se si usa Windows 11 e un processore moderno, selezionare x64 .NET 8 SDK per Windows.

Al termine del download, eseguire il programma di installazione e seguire le istruzioni. In una finestra del terminale eseguire il comando seguente per verificare che l'installazione sia riuscita:

dotnet --version

Verrà visualizzato il numero di versione di .NET SDK installato. Ad esempio:

8.0.300-preview.24203.14

Installare Visual Studio 2022 Preview

Seguire questo collegamento di Visual Studio 2022 Preview e selezionare Scarica anteprima. Al termine del download, eseguire il programma di installazione e seguire le istruzioni.

Installare Docker Desktop

Seguire questo collegamento a Docker Desktop e selezionare il programma di installazione corretto per il sistema operativo. Al termine del download, eseguire il programma di installazione e seguire le istruzioni.

Aprire l'applicazione Docker Desktop e accettare il contratto di servizio.

Installare il carico di lavoro .NET Aspire in Visual Studio

Installare il carico di lavoro .NET Aspire usando l'interfaccia della riga di comando di .NET:

  1. Aprire un terminale.

  2. Installare i carichi di lavoro .NET Aspire con questi comandi:

    dotnet workload update
    dotnet workload install aspire
    dotnet workload list
    

    Verranno visualizzati i dettagli del carico di lavoro .NET Aspire.

     Installed Workload Id      Manifest Version      Installation Source
    ---------------------------------------------------------------------------------------------
    aspire                     8.0.0/8.0.100         SDK 8.0.300-preview.24203, VS 17.10.34902.84
    
    Use `dotnet workload search` to find additional workloads to install.
    

Clonare e modificare l'app Northern Mountains

Si userà git per ottenere l'app Northern Mountains corrente:

  1. Nella riga di comando passare a una cartella di propria scelta in cui è possibile usare il codice.

  2. Eseguire il comando seguente per clonare l'applicazione di esempio Northern Mountains eShop:

    git clone -b aspire-databases https://github.com/MicrosoftDocs/mslearn-aspire-starter
    
  3. Avviare Visual Studio e quindi selezionare Apri un progetto o una soluzione.

  4. Passare alla cartella in cui è stato clonato l'eShop, aprire la cartella di Avvio e selezionare il file eShop.databases.sln e quindi selezionare Apri.

  5. In Esplora soluzioniespandere il progetto eShop.AppHost, quindi aprire Program.cs.

    // Databases
    
    var basketStore = builder.AddRedis("BasketStore").WithRedisCommander();
    
    // Identity Providers
    
    var idp = builder.AddKeycloakContainer("idp", tag: "23.0")
        .ImportRealms("../Keycloak/data/import");
    
    // DB Manager Apps
    
    builder.AddProject<Projects.Catalog_Data_Manager>("catalog-db-mgr");
    
    // API Apps
    
    var catalogApi = builder.AddProject<Projects.Catalog_API>("catalog-api");
    
    var basketApi = builder.AddProject<Projects.Basket_API>("basket-api")
            .WithReference(basketStore)
            .WithReference(idp);
    
    // Apps
    
    // Force HTTPS profile for web app (required for OIDC operations)
    var webApp = builder.AddProject<Projects.WebApp>("webapp")
        .WithReference(catalogApi)
        .WithReference(basketApi)
        .WithReference(idp, env: "Identity__ClientSecret");
    

    Il codice precedente mostra la configurazione corrente per l'app. L'app usa una cache Redis per l'archivio basket.

  6. Esplorare il resto dell'app, concentrarsi sui progetti Catalog.Data.Manager e Catalog.API e vedere come usano un database SQLite archiviato in locale.

  7. Per avviare l'app, premere F5 o selezionare Debug > Avvia debug.

  8. Se viene visualizzata la finestra di dialogo Avvia docker Desktop, selezionare .

  9. Quando viene visualizzato il dashboard di Windows Dev CentereShop .NET Aspire, per la risorsa App Web selezionare l’endpoint sicuro:

    Screenshot della dashboard eShop .NET Aspire. L'endpoint dell'app Web è evidenziato.

  10. L'app verrà aperta in un browser. È possibile esplorare l'app e vedere come funziona.

    Screenshot della home page di eShop.

    Le credenziali utente di test sono test@example.com e P@$$w0rd1.

  11. Per arrestare il debug, premere MAIUSC+F5 o selezionare Debug > Arresta debug.

Aggiungere un componente PostgreSQL aspirare a .NET

Il team responsabile dei microservizi del catalogo ha creato l'app per usare un database SQLite archiviato localmente. Questo approccio è adatto allo sviluppo, ma il team vuole usare un database più affidabile per la produzione.

Due progetti si connettono al database SQLite, i progetti Catalog.Data.Manager e Catalog.API. Il gestore dati viene usato solo per eseguire il seeding del database con i dati, quindi è consigliabile concentrarsi sul progetto Catalog.API.

  1. In Esplora soluzioni, fare clic con il pulsante destro del mouse sul progetto Catalog.API, scegliere Aggiungi>pacchetto .NET Aspire.

  2. Nella casella di Ricerca aggiungere Npgsql.EntityFramework alla fine e premere INVIO.

  3. A sinistra, nei risultati, selezionare Aspire.Npgsql.EntityFrameworkCore.PostgreSQL.

  4. A destra, selezionare l'elenco a discesa versione e quindi selezionare la versione 8.0.0 più recente.

  5. Selezionare Installa.

  6. Se viene visualizzata la finestra di dialogo Anteprima modifiche, selezionare Apply.

  7. Nella finestra di dialogo Accettazione della licenza selezionare Accetto.

  8. In Esplora soluzioniselezionare il progetto Catalog.API per visualizzare il contenuto del file Catalog.API.csproj.

  9. Eliminare per PackageReference per Microsoft.EntityFrameworkCore.Sqlite:

    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
    

Registrare il nuovo DbContext PostgreSQL

  1. In Esplora soluzioniespandere il progetto Catalog.API e quindi aprire il file Program.cs.

  2. Sostituire SQLite DbContext:

    builder.Services.AddDbContext<CatalogDbContext>(
         options => options.UseSqlite(builder.Configuration.GetConnectionString("sqlconnection")
     	    ?? throw new InvalidOperationException(
     		    "Connection string 'sqlconnection' not found.")));
    

    Con il nuovo DbContext PostgreSQL:

    builder.AddNpgsqlDbContext<CatalogDbContext>("CatalogDB");
    

    L'app non deve più leggere il file Database.db, quindi rimuovere le stringhe associate in appsettings.json.

  3. In Esplora soluzioni, in Catalog.API, selezionare appsettings.json.

  4. Eliminare le voci ConnectionStrings, il file avrà ora un aspetto simile al seguente:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "OpenApi": {
        "Endpoint": {
          "Name": "Catalog.API v1"
        },
        "Document": {
          "Description": "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample",
          "Title": "eShop - Catalog HTTP API",
          "Version": "v1"
        }
      },
      "CatalogOptions": {
        "PicBasePathFormat": "items/{0}/pic/"
      }
    }
    
    
  5. Fare clic con il pulsante destro del mouse sul progetto Catalog.Data.Manager e quindi scegliere Rimuovi.

  6. Nella finestra di dialogo selezionare OK.

Il team del database crea un backup del database PostgreSQL da usare per creare ed eseguire il seeding del database di catalogo. È possibile visualizzare il backup nella cartella Catalog.API/Seed.

Effettuare il seeding del database PostgreSQL usando un volume associato

Il progetto AppHost può creare un contenitore di database PostgreSQL, eseguirne il seeding con i dati di un volume associato e quindi tramite i riferimenti di inserimento delle dipendenze all'API Catalog.API.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto eShop.AppHost, selezionare Aggiungi>pacchetto .NET Aspire.

  2. Nella casella di Ricerca aggiungere PostgreSQL alla fine e premere INVIO.

  3. A sinistra, nei risultati selezionare Aspire.Hosting.PostgreSQL.

  4. A destra, selezionare l'elenco a discesa versione e quindi selezionare la versione 8.0.0 più recente.

  5. Selezionare Installa.

  6. Se viene visualizzata la finestra di dialogo Anteprima modifiche, selezionare Apply.

  7. Nella finestra di dialogo Accettazione della licenza selezionare Accetto.

  8. In Esplora soluzioniespandere il progetto eShop.AppHost e quindi aprire il file Program.cs.

  9. Sotto il commento //Databases, aggiungere il codice seguente:

    // Databases
    
    var basketStore = builder.AddRedis("BasketStore").WithRedisCommander();
    var postgres = builder.AddPostgres("postgres")
        .WithEnvironment("POSTGRES_DB", "CatalogDB")
        .WithBindMount("../Catalog.API/Seed", "/docker-entrypoint-initdb.d").WithPgAdmin();
    var catalogDB = postgres.AddDatabase("CatalogDB");
    

    Il codice precedente crea un contenitore di database PostgreSQL, aggiunge un database denominato CatalogDB e associa la directory /docker-entrypoint-initdb.d alla directory ../Catalog.API/Seed. Il codice crea anche un contenitore per lo strumento pgAdmin che consente di gestire il database PostgreSQL.

  10. Passare il riferimento catalogDB al progetto Catalog.API aggiungendo .WithReference(catalogDB), il codice è ora:

    // API Apps
    
    var catalogApi = builder.AddProject<Projects.Catalog_API>("catalog-api")
      .WithReference(catalogDB); 
    
  11. Il progetto Catalog.Data.Manager non è più necessario, quindi rimuovere il progetto da AppHost. Eliminare questo codice:

    // DB Manager Apps
    
    builder.AddProject<Projects.Catalog_Data_Manager>("catalog-db-mgr");
    

Testare l'app

L'uso di .NET Aspire ha consentito al team di rimuovere un intero progetto. Inoltre, l'API del catalogo richiede solo una singola riga di codice per aggiungere il contesto del database PostgresSQL. L'inserimento delle dipendenze e l'individuazione del servizio da AppHost indicano che non sono necessarie altre modifiche al codice per consentire all'API di connettersi al nuovo database.

  1. Compilare e avviare l'app, premere F5 o selezionare Debug > Avvia debug.

    Screenshot che mostra il dashboard .NET Aspire aggiornato, con i due nuovi contenitori PostgreSQL evidenziati.

    Nel dashboard sono presenti due nuovi contenitori che ospitano il server di database PostgreSQL e lo strumento pgAdmin. È disponibile anche una risorsa di database PostgreSQL che ospita il database CatalogDB.

  2. Usare pgAdmin per connettersi al database PostgreSQL ed esplorare i dati. Selezionare l'endpoint postgres pgadmin.

    Screenshot dell'interfaccia pgAdmin, che evidenzia lo spostamento alla tabella Catalogo.

  3. Espandere Istanze di Aspire>postgres >Database>CatalogDB>Schemi>catalogo>Tabelle. Fare quindi clic con il pulsante destro del mouse sulla tabella Catalogo e selezionare Visualizza/Modifica dati>Prime 100 righe.

  4. È possibile visualizzare i dati caricati da AppHost.

    Screenshot dell'interfaccia pgAdmin che mostra le righe restituite dalla tabella Catalog.

  5. Selezionare la scheda dashboard delle risorse eShop nel browser e quindi selezionare l'endpoint dell'app Web.

  6. L'app si apre e funziona come prima.

  7. Per arrestare il debug, premere MAIUSC+F5 o selezionare Debug > Arresta debug.

Aggiungere il componente MongoDB .NET Aspire all'app

L'app corrente usa Redis come archivio dati in memoria per il carrello della spesa di un cliente. Il team vuole usare un archivio dati più affidabile e durevole per il carrello. Sostituire la cache Redis con un database MongoDB.

Modificare Basket.API per usare MongoDB

  1. In Esplora soluzioni, fare clic con il pulsante destro del mouse sul progetto Basket.API, scegliere Aggiungi e quindi selezionare Aggiungi>pacchetto .NET Aspire.
  2. Nella casella Cerca immettere MongoDB alla fine e premere INVIO.
  3. Selezionare il driver Aspire.MongoDB.Driver e quindi selezionare la versione 8.0.0 più recente.
  4. Selezionare Installa.
  5. Se viene visualizzata la finestra di dialogo Anteprima modifiche, selezionare Apply.
  6. Nella finestra di dialogo Accettazione della licenza selezionare Accetto.@

Creare un archivio carrello MongoDB

Il microservizio carrello usa HostingExtensions per gestire l'archivio dati Redis. Sostituire l'archivio dati Redis con un archivio dati MongoDB.

  1. In Esplora soluzioniespandere il progetto Basket.API, quindi la cartella Archiviazione e quindi selezionare il file RedisBasketStore.cs.

    Esistono due metodi asincroni, GetBasketAsync e UpdateBasketAsync, che usano la cache Redis. Consente di creare versioni di MongoDB di questi metodi.

  2. In Esplora soluzioni, fare clic con il pulsante destro del mouse sulla cartella Archiviazione e quindi scegliere Aggiungi>classe.

  3. Nella finestra di dialogo Aggiungi nuovo elemento assegnare al file il nome MongoBasketStore.cs e quindi selezionare Aggiungi.

  4. Sostituire il codice nel file MongoBasketStore.cs con il codice seguente:

    using eShop.Basket.API.Models;
    using MongoDB.Driver;
    using MongoDB.Driver.Linq;
    
    namespace eShop.Basket.API.Storage;
    
    public class MongoBasketStore
    {
      private readonly IMongoCollection<CustomerBasket> _basketCollection;
    
      public MongoBasketStore(IMongoClient mongoClient)
      {
        // The database name needs to match the created database in the AppHost
        _basketCollection = mongoClient.GetDatabase("BasketDB").GetCollection<CustomerBasket>("basketitems");
      }
    
      public async Task<CustomerBasket?> GetBasketAsync(string customerId)
      {
        var filter = Builders<CustomerBasket>.Filter.Eq(r => r.BuyerId, customerId);
    
        return await _basketCollection.Find(filter).FirstOrDefaultAsync();
      }
    
      public async Task<CustomerBasket?> UpdateBasketAsync(CustomerBasket basket)
      {
        var filter = Builders<CustomerBasket>.Filter.Eq(r => r.BuyerId, basket.BuyerId);
    
        var result = await _basketCollection.ReplaceOneAsync(filter, basket, new ReplaceOptions { IsUpsert = true });
    
        return result.IsModifiedCountAvailable ? basket : null;
      }
    }
    

    Il codice precedente crea una classe MongoBasketStore che funziona con il modello CustomerBasket. La raccolta gestisce le operazioni CRUD per i carrelli della spesa dei clienti in un database MongoDB.

  5. In Esplora soluzioniespandere le estensioni>Basket.API e quindi selezionare il file HostingExtensions.cs.

  6. Sostituire il codice Redis:

    builder.AddRedis("BasketStore");
    
    builder.Services.AddSingleton<RedisBasketStore>();
    

    Con il codice MongoDB:

    builder.AddMongoDBClient("BasketDB");
    
    builder.Services.AddSingleton<MongoBasketStore>();
    
  7. In Esplora soluzioniespandere la cartella Grpc e quindi aprire il file BasketService.cs.

  8. Modificare la classe in modo da accettare un oggetto MongoBasketStore, sostituire:

    public class BasketService(RedisBasketStore basketStore) : Basket.BasketBase
    

    Con:

    public class BasketService(MongoBasketStore basketStore) : Basket.BasketBase
    

Aggiungere un database MongoDB ad AppHost

  1. In Esplora soluzioni, fare clic con il pulsante destro del mouse sul progetto eShop.AppHost e scegliere Aggiungi>pacchetto .NET Aspire.

  2. Nella casella Cerca immettere MongoDB alla fine e premere INVIO.

  3. Selezionare il pacchetto Aspire.Hosting.MongoDB e quindi selezionare la versione 8.0.0 più recente.

  4. Selezionare Installa.

  5. Se viene visualizzata la finestra di dialogo Anteprima modifiche, selezionare Apply.

  6. Nella finestra di dialogo Accettazione della licenza selezionare Accetto.@

  7. In Esplora soluzioniespandere il progetto eShop.AppHost e quindi aprire il file Program.cs.

  8. Nella sezione Database aggiungere un componente MongoDB:

    var mongo = builder.AddMongoDB("mongo")
      .WithMongoExpress()
      .AddDatabase("BasketDB");
    

    Il codice precedente crea un contenitore di database MongoDB, aggiunge un database denominato BasketDB. Il codice crea anche un contenitore per lo strumento Mongo Express che consente di gestire il database MongoDB.

  9. Eliminare il contenitore Redis:

    var basketStore = builder.AddRedis("BasketStore").WithRedisCommander();
    

    Il codice dovrebbe apparire come illustrato di seguito:

    // Databases
    
    var postgres = builder.AddPostgres("postgres")
        .WithEnvironment("POSTGRES_DB", "CatalogDB")
        .WithBindMount("../Catalog.API/Seed", "/docker-entrypoint-initdb.d")
        .WithPgAdmin();
    var catalogDB = postgres.AddDatabase("CatalogDB");
    
    var mongo = builder.AddMongoDB("mongo")
        .WithMongoExpress()
        .AddDatabase("BasketDB");
    
  10. Il progetto Basket.API richiede un riferimento al nuovo database MongoDB ed è necessario rimuovere il riferimento a Redis:

    var basketApi = builder.AddProject<Projects.Basket_API>("basket-api")
            .WithReference(mongo)
            .WithReference(idp);
    

Il progetto Basket.API è ora pronto per l'uso del database MongoDB. Testare l'app per verificare se funziona.

Testare l'app

  1. Compilare e avviare l'app, premere F5 o selezionare Debug > Avvia debug.

    Screenshot del dashboard .NET Aspire con i contenitori MongoDB evidenziati.

    È possibile visualizzare i nuovi contenitori MongoDB, uno per il server di database l'altro per Mongo Express, nel dashboard. È disponibile anche una nuova risorsa MongoDBDatabase che ospita il database BasketDB.

  2. Selezionare l'endpoint dell'app Web.

  3. Per accedere con le credenziali utente di test, selezionare l'icona dell'utente in alto a destra. Il messaggio di posta elettronica è test@example.com e la password è P@$$w0rd1.

  4. Selezionare l'orologio GPS Adventurer dalla home page.

  5. Selezionare Aggiungi al carrello della spesa. Dovrebbe essere visualizzata un'eccezione:

    Screenshot che mostra RpcException.

Eseguire il debug dell'app

L'app genera un'eccezione quando si tenta di aggiungere un elemento al carrello della spesa. È possibile usare il dashboard per eseguire il debug del problema.

  1. Selezionare la scheda dashboard delle risorse eShop nel browser.

    Screenshot del dashboard, gli errori nell'app Basket.API e web sono evidenziati.

    Il dashboard mostra gli errori nella basket-api e nell'app Web. Esaminare i log per la basket-api.

  2. Per la risorsa basket-api, nella colonna Log selezionare Visualizza.

    Screenshot dei log per il servizio basket-api.

    Esiste un'eccezione:

    System.FormatException: Element '_id' does not match any field or property of class eShop.Basket.API.Models.CustomerBasket.
    
  3. Selezionare la voce di menu Risorse e quindi selezionare l'endpoint mongo-mongoexpress.

  4. Nella sezione Database, accanto a BasketDB, selezionare Visualizza.

  5. In Raccolte, accanto a basketitems, selezionare Visualizza.

    Screenshot di Mongo Express che mostra i dati archiviati nella raccolta basketitems.

    I documenti archiviati in mongoDB hanno un campo _id. Ogni documento archiviato in una raccolta MongoDB deve avere un campo _id univoco.

  6. Per arrestare il debug, premere MAIUSC+F5 o selezionare Debug > Arresta debug.

Esaminare il codice e risolvere il problema

Esaminiamo il CustomerBasket e vediamo se è possibile trovare il problema.

  1. In Esplora soluzioniespandere la cartella Basket.API>Modelli e quindi aprire il file CustomerBasket.cs.

    public class CustomerBasket
    {
        public required string BuyerId { get; set; }
    
        public List<BasketItem> Items { get; set; } = [];
    }
    

    Il modello CustomerBasket non ha un campo o una proprietà corrispondente al campo _id. Entity Framework sta tentando di eseguire il mapping del campo _id al modello CustomerBasket e non riesce a trovare una corrispondenza.

  2. Aggiornare il modello CustomerBasket in modo da includere un campo _id:

    public class CustomerBasket
    {
        /// <summary>
        /// MongoDB document identifier
        /// </summary>
        public string _id { get; set; } = "";
    
        public required string BuyerId { get; set; }
    
        public List<BasketItem> Items { get; set; } = [];
    }
    

Testare l'app fissa

  1. Per compilare e avviare l'app, premere F5 o selezionare Debug > Avvia debug.

  2. Per l'app Web, nella colonna Endpoint, fare clic con il pulsante destro del mouse sull'URL e quindi scegliere Apri collegamento in Finestra InPrivate.

    L'uso di una finestra InPrivate garantisce che il browser non usi il cookie di sessione precedente per l'autenticazione.

  3. Per accedere con le credenziali utente di test, selezionare l'icona dell'utente in alto a destra. Il messaggio di posta elettronica è test@example.com e la password è P@$$w0rd1.

  4. Selezionare l'orologio GPS Adventurer dalla home page.

  5. Selezionare Aggiungi al carrello della spesa.

    Screenshot del carrello della spesa eShop funzionante.

    La funzionalità carello della spesa dell'app Northern Mountains ora funziona.

Il database SQLite è stato sostituito correttamente con un database PostgreSQL e la cache Redis con un database MongoDB. È stato usato .NET Aspire per gestire i database ed esplorare i dati in essi contenuti ed è stato usato il dashboard per facilitare il debug di un problema con l'app.