Ejercicio: Uso de servicios de base de datos para conservar datos de un proyecto de .NET Aspire
En este ejercicio, reemplazará los almacenes de datos actuales de la aplicación nativa de nube en desarrollo de su empresa. En este momento, la aplicación usa una base de datos de SQLite almacenada localmente para los datos del catálogo y una caché en memoria de Redis para los carros de la compra del cliente. Reemplazará los almacenes de datos existentes por PostgreSQL y MongoDB.
Requisitos previos de instalación
Los requisitos previos para .NET Aspire son:
- .NET 8
- Versión preliminar de Visual Studio 2022
- Docker Desktop o Podman
- Carga de trabajo de .NET Aspire en Visual Studio
Si ya tiene instalados los requisitos previos, puede pasar directamente a clonar la aplicación existente.
Instalación de .NET 8
Siga este vínculo de .NET 8 y seleccione el instalador correcto para el sistema operativo. Por ejemplo, si usa Windows 11 y un procesador moderno, seleccione el SDK de .NET 8 para Windows x64.
Una vez completada la descarga, ejecute el instalador y siga las instrucciones. En una ventana de terminal, ejecute el siguiente comando para comprobar que la instalación se realizó correctamente:
dotnet --version
Debería ver el número de versión del SDK de .NET que instaló. Por ejemplo:
8.0.300-preview.24203.14
Instalación de Visual Studio 2022 Preview
Siga este vínculo de Visual Studio 2022 Preview y seleccione Descargar versión preliminar. Una vez completada la descarga, ejecute el instalador y siga las instrucciones.
Instalar Docker Desktop
Siga este vínculo de Docker Desktop y seleccione el instalador correcto para el sistema operativo. Una vez completada la descarga, ejecute el instalador y siga las instrucciones.
Abra la aplicación Docker Desktop y acepte el contrato de servicio.
Instalación de la carga de trabajo de .NET Aspire en Visual Studio
Instale la carga de trabajo de .NET Aspire mediante la CLI de NET:
Abra un terminal.
Instale las cargas de trabajo de .NET Aspire con estos comandos:
dotnet workload update dotnet workload install aspire dotnet workload list
Debería ver los detalles de la carga de trabajo de .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.
Clonación y modificación de la aplicación Northern Mountains
Vamos a usar git
para obtener la aplicación Northern Mountains actual:
En la línea de comandos, vaya a una carpeta de su elección, donde pueda trabajar con código.
Ejecute el siguiente comando para clonar la aplicación de ejemplo Northern Mountains eShop:
git clone -b aspire-databases https://github.com/MicrosoftDocs/mslearn-aspire-starter
Inicie Visual Studio y después seleccione Abrir un proyecto o solución.
Vaya a la carpeta donde ha clonado eShop, abra la carpeta de inicio y seleccione el archivo eShop.databases.sln y, a continuación, seleccione Abrir.
En el Explorador de soluciones, expanda el proyecto eShop.AppHost y, después, abra el archivo 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");
El código anterior muestra la configuración actual de la aplicación. La aplicación usa Redis Cache para el almacenamiento de los carros de la compra.
Explore el resto de la aplicación, céntrese en los proyectos Catalog.Data.Manager y Catalog.API y vea cómo usan una base de datos de SQLite almacenada localmente.
Para iniciar la aplicación, presione F5 o seleccione Depurar > Iniciar depuración.
Si aparece el cuadro de diálogo Iniciar Docker Desktop, seleccione Sí.
Cuando aparezca el panel eShop de .NET Aspire, del recurso de aplicación web, seleccione el punto de conexión seguro:
La aplicación se abre en un explorador. Puede explorar la aplicación y ver cómo funciona.
Las credenciales de usuario de prueba son test@example.com y P@$$w0rd1.
Para detener la depuración, presione Mayús+F5 o seleccione Depurar > Detener depuración.
Adición de un componente de PostgreSQL para .NET Aspire
El equipo responsable de los microservicios de catálogo creó la aplicación para que usara una base de datos de SQLite almacenada localmente. Este enfoque es adecuado para el desarrollo, pero el equipo quiere usar una base de datos más sólida para producción.
Dos proyectos se conectan a la base de datos de SQLite: Catalog.Data.Manager y Catalog.API. Data Manager solo se usa para proveer la base de datos con datos, por lo que debe centrarse en el proyecto Catalog.API.
En el Explorador de soluciones, haga clic con el botón derecho en el proyecto Catalog.API, seleccione Agregar>Paquete de .NET Aspire.
En el cuadro Buscar, agregue Npgsql.EntityFramework al final y presione Entrar.
A la izquierda, en los resultados, seleccione Aspire.Npgsql.EntityFrameworkCore.PostgreSQL.
A la derecha, seleccione la lista desplegable de versiones y, a continuación, seleccione la versión más reciente: 8.0.0.
Seleccione Instalar.
Si aparece el cuadro de diálogo Vista previa de cambios, seleccione Aplicar.
En el diálogo Aceptación de licencia, seleccione Acepto.
En el Explorador de soluciones, seleccione el proyecto Catalog.API para ver el contenido del archivo Catalog.API.csproj.
Elimine
PackageReference
de Microsoft.EntityFrameworkCore.Sqlite:<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
Registro del nuevo PostgreSQL DbContext
En el Explorador de soluciones, expanda el proyecto Catalog.API y, a continuación, abra el archivo Program.cs.
Reemplace SQLite DbContext:
builder.Services.AddDbContext<CatalogDbContext>( options => options.UseSqlite(builder.Configuration.GetConnectionString("sqlconnection") ?? throw new InvalidOperationException( "Connection string 'sqlconnection' not found.")));
Por el nuevo PostgreSQL DbContext:
builder.AddNpgsqlDbContext<CatalogDbContext>("CatalogDB");
La aplicación ya no necesita leer el archivo Database.db, por lo que elimina las cadenas asociadas en appsettings.json.
En el Explorador de soluciones, en Catalog.API, seleccione appsettings.json.
Elimine las entradas
ConnectionStrings
y el archivo tendrá el siguiente aspecto:{ "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/" } }
Haga clic con el botón derecho en el proyecto Catalog.Data.Manager y seleccione Eliminar.
En el cuadro de diálogo, seleccione Aceptar.
El equipo de base de datos crea una copia de seguridad de la base de datos de PostgreSQL que se usará para crear y proveer la base de datos del catálogo. Puede ver la copia de seguridad en la carpeta Catalog.API/Seed.
Proveer la base de datos de PostgreSQL mediante un volumen limitado
El proyecto AppHost puede crear un contenedor de bases de datos de PostgreSQL, proporcionarle datos de un volumen limitado y, a continuación, pasar referencias mediante la inserción de dependencias en el proyecto Catalog.API.
En el Explorador de soluciones, haga clic con el botón derecho en el proyecto eShop.AppHost, seleccione Agregar>Paquete de .NET Aspire.
En el cuadro de búsqueda, agregue PostgreSQL al final y presione Entrar.
A la izquierda, en los resultados, seleccione Aspire.Hosting.PostgreSQL.
A la derecha, seleccione la lista desplegable de versiones y, a continuación, seleccione la versión más reciente: 8.0.0.
Seleccione Instalar.
Si aparece el cuadro de diálogo Vista previa de cambios, seleccione Aplicar.
En el diálogo Aceptación de licencia, seleccione Acepto.
En el Explorador de soluciones, expanda el proyecto eShop.AppHost y, a continuación, abra el archivo Program.cs.
En el comentario
//Databases
, agregue el código siguiente:// 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");
El código anterior crea un contenedor de bases de datos de PostgreSQL, agrega una base de datos denominada CatalogDB y enlaza el directorio /docker-entrypoint-initdb.d al directorio ../Catalog.API/Seed. El código también crea un contenedor para la herramienta pgAdmin que le permite administrar la base de datos de PostgreSQL.
Pase la referencia
catalogDB
al proyecto Catalog.API agregando.WithReference(catalogDB)
. El código ahora es:// API Apps var catalogApi = builder.AddProject<Projects.Catalog_API>("catalog-api") .WithReference(catalogDB);
El proyecto Catalog.Data.Manager ya no es necesario, por lo que puede eliminarlo de AppHost. Elimine este código:
// DB Manager Apps builder.AddProject<Projects.Catalog_Data_Manager>("catalog-db-mgr");
Prueba de la aplicación
El uso de .NET Aspire permitió al equipo eliminar un proyecto completo. Además, la API de catálogo solo necesita una única línea de código para agregar el contexto de base de datos de PostgresSQL. La inserción de dependencias y la detección de servicios de AppHost significa que no se necesitan otros cambios de código para permitir que la API se conecte a la nueva base de datos.
Compile e inicie la aplicación, presione F5 o seleccione Depurar > Iniciar depuración.
Hay dos contenedores nuevos en el panel que hospedan el servidor de bases de datos de PostgreSQL y la herramienta pgAdmin. También hay un recurso de base de datos de PostgreSQL que hospeda la base de datos CatalogDB.
Use pgAdmin para conectarse a la base de datos de PostgreSQL y explorar los datos. Seleccione el punto de conexión postgres pgadmin.
Expanda Instancias de Aspire>postgres>Bases de datos>CatalogDB>Esquemas>catalog>Tablas. A continuación, haga clic con el botón derecho en la tabla Catalog y seleccione Ver y editar datos>Primeras 100 filas.
Puede ver los datos cargados por AppHost.
Seleccione la pestaña Recursos de eShop del panel en el explorador y, a continuación, seleccione el punto de conexión webapp.
La aplicación se abre y funciona como antes.
Para detener la depuración, presione Mayús+F5 o seleccione Depurar > Detener depuración.
Adición del componente MongoDB de .NET Aspire a la aplicación
La aplicación actual usa Redis como almacén de datos en memoria para el carro de la compra de un cliente. El equipo quiere usar un almacén de datos más sólido y duradero para el carro de la compra. Reemplace Redis Cache por una base de datos de MongoDB.
Cambio de Basket.API para que use MongoDB
- En el Explorador de soluciones, haga clic con el botón derecho en el proyecto Basket.API, seleccione Agregar y, a continuación, seleccioneAgregar>Paquete de .NET Aspire.
- En el cuadro de búsqueda, escriba MongoDB al final y presione Entrar.
- Seleccione Aspire.MongoDB.Driver y, después, seleccione la versión más reciente: 8.0.0.
- Seleccione Instalar.
- Si aparece el cuadro de diálogo Vista previa de cambios, seleccione Aplicar.
- En el cuadro de diálogo Aceptación de licencia, seleccione Acepto.
Creación de un almacén de carros de la compra de MongoDB
El microservicio de carros de la compra usa HostingExtensions
para administrar el almacén de datos de Redis. Reemplace el almacén de datos de Redis por un almacén de datos de MongoDB.
En el Explorador de soluciones, expanda el proyecto Basket.API, después la carpeta Storage y, finalmente, seleccione el archivo RedisBasketStore.cs.
Hay dos métodos asincrónicos,
GetBasketAsync
yUpdateBasketAsync
, que usan Redis Cache. Vamos a crear versiones de MongoDB de estos métodos.En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Almacenamiento y seleccione Agregar>Clase.
En el cuadro de diálogo Agregar nuevo elemento, asigne el nombre MongoBasketStore.cs al archivo y, a continuación, seleccione Agregar.
Reemplace el código del archivo MongoBasketStore.cs por el código siguiente:
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; } }
El código anterior crea una clase
MongoBasketStore
que funciona con el modeloCustomerBasket
. La colección controla las operaciones CRUD de los carros de la compra de los clientes en una base de datos de MongoDB.En el Explorador de soluciones, expanda Basket.API>Extensiones y, a continuación, seleccione el archivo HostingExtensions.cs.
Reemplace el código de Redis:
builder.AddRedis("BasketStore"); builder.Services.AddSingleton<RedisBasketStore>();
Con el código de MongoDB:
builder.AddMongoDBClient("BasketDB"); builder.Services.AddSingleton<MongoBasketStore>();
En el Explorador de soluciones, expanda la carpeta Grpc y abra el archivo BasketService.cs.
Cambie la clase para aceptar un
MongoBasketStore
y reemplace:public class BasketService(RedisBasketStore basketStore) : Basket.BasketBase
Por:
public class BasketService(MongoBasketStore basketStore) : Basket.BasketBase
Adición de una base de datos de MongoDB a AppHost
En el Explorador de soluciones, haga clic con el botón derecho en el proyecto eShop.AppHost y seleccione Agregar>Paquete de .NET Aspire.
En el cuadro de búsqueda, escriba MongoDB al final y presione Entrar.
Seleccione el paquete Aspire.Hosting.MongoDB y, después, seleccione la versión más reciente: 8.0.0.
Seleccione Instalar.
Si aparece el cuadro de diálogo Vista previa de cambios, seleccione Aplicar.
En el cuadro de diálogo Aceptación de licencia, seleccione Acepto.
En el Explorador de soluciones, expanda el proyecto eShop.AppHost y, a continuación, abra el archivo Program.cs.
En la sección Bases de datos, agregue un componente de MongoDB:
var mongo = builder.AddMongoDB("mongo") .WithMongoExpress() .AddDatabase("BasketDB");
El código anterior crea un contenedor de bases de datos de MongoDB y agrega una base de datos denominada BasketDB. El código también crea un contenedor para la herramienta Mongo Express que le permite administrar la base de datos de MongoDB.
Elimine el contenedor de Redis:
var basketStore = builder.AddRedis("BasketStore").WithRedisCommander();
El código ahora debería presentar un aspecto similar a este:
// 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");
El proyecto Basket.API necesita una referencia a la nueva base de datos de MongoDB y debe quitar la referencia de Redis:
var basketApi = builder.AddProject<Projects.Basket_API>("basket-api") .WithReference(mongo) .WithReference(idp);
El proyecto Basket.API ya está listo para usar la base de datos de MongoDB. Vamos a probar la aplicación para ver si funciona.
Prueba de la aplicación
Compile e inicie la aplicación, presione F5 o seleccione Depurar > Iniciar depuración.
Puede ver los nuevos contenedores de MongoDB, uno para el servidor de bases de datos el otro para Mongo Express, en el panel. También hay un nuevo recurso MongoDBDatabase que hospeda la base de datos BasketDB.
Seleccione el punto de conexión webapp.
Para iniciar sesión con las credenciales del usuario de prueba, seleccione el icono de usuario en la parte superior derecha. El correo electrónico es test@example.com y la contraseña es P@$$w0rd1.
Seleccione el producto Reloj GPS Adventurer en la página principal.
Seleccione Agregar a cesta de compras y debería aparecer una excepción:
Depurar la aplicación
La aplicación produce una excepción al intentar agregar un artículo al carro de la compra. Puede usar el panel para ayudar a depurar el problema.
Seleccione la pestaña Recursos de eShop del panel en el explorador.
El panel muestra errores en basket-api y webapp. Revise los registros de basket-api.
Para el recurso basket-api, de la columna Logs, seleccione Ver.
Hay una excepción:
System.FormatException: Element '_id' does not match any field or property of class eShop.Basket.API.Models.CustomerBasket.
Seleccione el elemento de menú Recursos y, a continuación, seleccione el punto de conexión mongo-mongoexpress.
En la sección Bases de datos, junto a BasketDB, seleccione Ver.
En Colecciones, junto a basketitems, seleccione Ver.
Los documentos almacenados en MongoDB tienen un campo _id. Todos los documentos almacenados en una colección de MongoDB deben tener un campo _id único.
Para detener la depuración, presione Mayús+F5 o seleccione Depurar > Detener depuración.
Revisión del código y corrección del problema
Echemos un vistazo a CustomerBasket y veamos si podemos encontrar el problema.
En el Explorador de soluciones, expanda la carpeta Basket.API>Modelos y abra el archivo CustomerBasket.cs.
public class CustomerBasket { public required string BuyerId { get; set; } public List<BasketItem> Items { get; set; } = []; }
El modelo CustomerBasket no tiene un campo o propiedad que coincida con el campo _id. Entity Framework está intentando asignar el campo _id al modelo CustomerBasket y no puede encontrar ninguna coincidencia.
Actualice el modelo
CustomerBasket
para que incluya 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; } = []; }
Probar la aplicación corregida
Para compilar e iniciar la aplicación, presione F5 o seleccione Depurar > Iniciar depuración.
Para webapp, en la columna Endpoints, haga clic con el botón derecho en la dirección URL y, a continuación, seleccione Abrir vínculo en la ventana InPrivate.
El uso de una ventana InPrivate garantiza que el explorador no use la cookie de la sesión anterior para la autenticación.
Para iniciar sesión con las credenciales del usuario de prueba, seleccione el icono de usuario en la parte superior derecha. El correo electrónico es test@example.com y la contraseña es P@$$w0rd1.
Seleccione el producto Reloj GPS Adventurer en la página principal.
Seleccione Agregar a la cesta de compras.
La funcionalidad de carro de la compra de la aplicación Northern Mountains ahora funciona.
Ha reemplazado correctamente la base de datos de SQLite por una base de datos de PostgreSQL y la instancia de Redis Cache por una base de datos de MongoDB. Ha usado .NET Aspire para administrar las bases de datos y explorar los datos que hay en ellas y ha usado el panel para ayudar a depurar un problema con la aplicación.