연습 - 데이터베이스 서비스를 사용하여 .NET Aspire 프로젝트의 데이터 유지
이 연습에서는 회사에서 개발 중인 클라우드 네이티브 앱의 현재 데이터 저장소를 바꿉니다. 현재 앱은 카탈로그 데이터를 위해 로컬에 저장된 SQLite 데이터베이스를 사용하고 고객의 장바구니를 위해 메모리 내 Redis Cache를 사용합니다. 기존 데이터 저장소를 PostgreSQL 및 MongoDB로 바꿉니다.
필수 구성 요소 설치
.NET Aspire의 필수 조건은 다음과 같습니다.
- .NET 8
- Visual Studio 2022 미리 보기
- Docker Desktop 또는 Podman
- Visual Studio의 .NET Aspire 워크로드
필수 구성 요소가 이미 설치되어 있는 경우 기존 앱 복제로 건너뛸 수 있습니다.
.NET 8 설치
이 .NET 8 링크를 따라가서 운영 체제에 맞는 올바른 설치 프로그램을 선택합니다. 예를 들어, Windows 11과 최신 프로세서를 사용하는 경우 Windows용 x64 .NET 8 SDK를 선택합니다.
다운로드가 완료되면 설치 프로그램을 실행하고 지침을 따릅니다. 터미널 창에서 다음 명령을 실행하여 설치가 성공했는지 확인합니다.
dotnet --version
설치한 .NET SDK의 버전 번호가 표시되어야 합니다. 예시:
8.0.300-preview.24203.14
Visual Studio 2022 Preview 설치
이 Visual Studio 2022 미리 보기 링크를 따라가서 미리 보기 다운로드를 선택합니다. 다운로드가 완료되면 설치 프로그램을 실행하고 지침을 따릅니다.
Docker Desktop 설치
이 Docker Desktop 링크를 따라가서 운영 체제에 맞는 올바른 설치 프로그램을 선택합니다. 다운로드가 완료되면 설치 프로그램을 실행하고 지침을 따릅니다.
Docker Desktop 애플리케이션을 열고 서비스 계약에 동의합니다.
Visual Studio에서 .NET Aspire 워크로드 설치
.NET CLI를 사용하여 .NET Aspire 워크로드를 설치합니다.
터미널을 엽니다.
다음 명령을 사용하여 .NET Aspire 워크로드를 설치합니다.
dotnet workload update dotnet workload install aspire dotnet workload list
.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.
Northern Mountains 앱 복제 및 수정
현재 Northern Mountains 앱을 가져오기 위해 git
를 사용해 보겠습니다.
명령줄에서 코드 작업을 할 수 있는 폴더를 선택합니다.
다음 명령을 실행하여 Northern Mountains eShop 샘플 애플리케이션을 복제합니다.
git clone -b aspire-databases https://github.com/MicrosoftDocs/mslearn-aspire-starter
Visual Studio를 시작한 다음 프로젝트 또는 솔루션 열기를 선택합니다.
eShop을 복제한 폴더를 찾아 start 폴더를 열고 eShop.databases.sln 파일을 선택한 다음 열기를 선택합니다.
솔루션 탐색기에서 eShop.AppHost 프로젝트를 확장한 다음 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");
이전 코드는 앱의 현재 구성을 보여 줍니다. 앱은 장바구니 저장소에 Redis Cache를 사용합니다.
앱의 나머지 부분을 살펴보고 Catalog.Data.Manager 및 Catalog.API 프로젝트에 중점을 두고 로컬에 저장된 SQLite 데이터베이스를 어떻게 사용하는지 확인합니다.
앱을 시작하려면 F5를 누르거나 디버그 > 디버깅 시작을 선택합니다.
Docker Desktop 시작 대화 상자가 나타나면 예를 선택합니다.
eShop .NET Aspire 대시보드가 나타나면 webapp 리소스에 대해 보안 엔드포인트를 선택합니다.
앱이 브라우저에서 열립니다. 앱을 탐색하고 작동 방식을 확인할 수 있습니다.
테스트 사용자 자격 증명은 test@example.com 및 P@$$w0rd1입니다.
디버깅을 중지하려면 Shift+F5를 누르거나 디버그 > 디버깅 중지를 선택합니다.
.NET Aspire PostgreSQL 구성 요소 추가
카탈로그 마이크로 서비스를 담당하는 팀은 로컬에 저장된 SQLite 데이터베이스를 사용하도록 앱을 빌드했습니다. 이 방식은 개발에는 적합하지만 팀은 프로덕션에 보다 강력한 데이터베이스를 사용하려고 합니다.
두 개의 프로젝트(Catalog.Data.Manager 및 Catalog.API 프로젝트)가 SQLite 데이터베이스에 연결됩니다. Data Manager는 데이터베이스에 데이터를 시드하는 데만 사용되므로 Catalog.API 프로젝트에 집중해야 합니다.
솔루션 탐색기에서 Catalog.API 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가>.NET Aspire 패키지를 선택합니다.
검색 상자에서 끝에 Npgsql.EntityFramework를 추가하고 Enter 키를 누릅니다.
왼쪽 결과에서 Aspire.Npgsql.EntityFrameworkCore.PostgreSQL을 선택합니다.
오른쪽에서 버전 드롭다운을 선택한 다음 최신 8.0.0 릴리스를 선택합니다.
설치를 선택합니다.
변경 내용 미리 보기 대화 상자가 표시되면 적용을 선택합니다.
라이선스 동의 대화 상자에서 동의함을 선택합니다.
솔루션 탐색기에서 Catalog.API 프로젝트를 선택하여 Catalog.API.csproj 파일의 콘텐츠를 확인합니다.
Microsoft.EntityFrameworkCore.Sqlite에 대한
PackageReference
를 삭제합니다.<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
새 PostgreSQL DbContext 등록
솔루션 탐색기에서 Catalog.API 프로젝트를 확장한 다음 Program.cs 파일을 엽니다.
SQLite DbContext를 바꿉니다.
builder.Services.AddDbContext<CatalogDbContext>( options => options.UseSqlite(builder.Configuration.GetConnectionString("sqlconnection") ?? throw new InvalidOperationException( "Connection string 'sqlconnection' not found.")));
새로운 PostgreSQL DbContext를 사용하면 다음과 같습니다.
builder.AddNpgsqlDbContext<CatalogDbContext>("CatalogDB");
앱은 더 이상 Database.db 파일을 읽을 필요가 없으므로 appsettings.json에서 관련 문자열을 제거합니다.
솔루션 탐색기의 Catalog.API에서 appsettings.json을 선택합니다.
ConnectionStrings
항목을 삭제하면 파일은 이제 다음과 같습니다.{ "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/" } }
Catalog.Data.Manager 프로젝트를 마우스 오른쪽 단추로 클릭한 다음 제거를 선택합니다.
대화 상자에서 확인을 선택합니다.
데이터베이스 팀은 카탈로그 데이터베이스를 만들고 시드하는 데 사용할 PostgreSQL 데이터베이스 백업을 만듭니다. Catalog.API/Seed 폴더에서 백업을 볼 수 있습니다.
바인딩된 볼륨을 사용하여 PostgreSQL 데이터베이스 시드
AppHost 프로젝트는 PostgreSQL 데이터베이스 컨테이너를 만들고 바인딩된 볼륨의 데이터를 여기에 시드한 다음 종속성 주입을 통해 Catalog.API에 대한 참조를 전달할 수 있습니다.
솔루션 탐색기에서 eShop.AppHost 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가>.NET Aspire 패키지를 선택합니다.
검색 상자의 끝에 PostgreSQL을 추가하고 Enter 키를 누릅니다.
왼쪽 결과에서 Aspire.Hosting.PostgreSQL을 선택합니다.
오른쪽에서 버전 드롭다운을 선택한 다음 최신 8.0.0 릴리스를 선택합니다.
설치를 선택합니다.
변경 내용 미리 보기 대화 상자가 표시되면 적용을 선택합니다.
라이선스 동의 대화 상자에서 동의함을 선택합니다.
솔루션 탐색기에서 eShop.AppHost 프로젝트를 확장한 다음 Program.cs 파일을 엽니다.
//Databases
주석 아래에 다음 코드를 추가합니다.// 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");
이전 코드는 PostgreSQL 데이터베이스 컨테이너를 만들고, CatalogDB라는 데이터베이스를 추가하고 /docker-entrypoint-initdb.d 디렉터리를 ../Catalog.API/Seed 디렉터리에 바인딩합니다. 또한 이 코드는 PostgreSQL 데이터베이스를 관리할 수 있는 pgAdmin 도구용 컨테이너를 만듭니다.
.WithReference(catalogDB)
를 추가하여catalogDB
참조를 Catalog.API 프로젝트에 전달합니다. 이제 코드는 다음과 같습니다.// API Apps var catalogApi = builder.AddProject<Projects.Catalog_API>("catalog-api") .WithReference(catalogDB);
Catalog.Data.Manager 프로젝트는 더 이상 필요하지 않으므로 AppHost에서 프로젝트를 제거합니다. 이 코드를 삭제합니다.
// DB Manager Apps builder.AddProject<Projects.Catalog_Data_Manager>("catalog-db-mgr");
앱 테스트
.NET Aspire를 사용하면 팀에서 전체 프로젝트를 제거할 수 있습니다. 또한 카탈로그 API에는 PostgresQL 데이터베이스 컨텍스트를 추가하는 데 한 줄의 코드만 필요합니다. AppHost의 종속성 주입 및 서비스 검색은 API가 새 데이터베이스에 연결되도록 허용하기 위해 다른 코드 변경이 필요하지 않음을 의미합니다.
앱을 컴파일하고 시작하거나 F5를 누르거나 디버그 >디버깅 시작을 선택합니다.
대시보드에는 PostgreSQL 데이터베이스 서버와 pgAdmin 도구를 호스팅하는 두 개의 새로운 컨테이너가 있습니다. CatalogDB 데이터베이스를 호스팅하는 PostgreSQL 데이터베이스 리소스도 있습니다.
pgAdmin을 사용하여 PostgreSQL 데이터베이스에 연결하고 데이터를 살펴봅니다. postgres pgadmin 엔드포인트를 선택합니다.
Aspire 인스턴스>postgres>데이터베이스>CatalogDB>스키마>카탈로그>테이블을 확장합니다. 그런 다음 카탈로그 표를 마우스 오른쪽 단추로 클릭하고 데이터 보기/편집>처음 100개 행을 선택합니다.
AppHost에 의해 로드된 데이터를 볼 수 있습니다.
브라우저에서 eShop 리소스 대시보드 탭을 선택한 다음 webapp 엔드포인트를 선택합니다.
앱이 열리고 이전과 같이 작동합니다.
디버깅을 중지하려면 Shift+F5를 누르거나 디버그 > 디버깅 중지를 선택합니다.
앱에 .NET Aspire MongoDB 구성 요소 추가
현재 앱은 Redis를 고객의 장바구니에 대한 메모리 내 데이터 저장소로 사용합니다. 팀에서 바구니에 더욱 강력하고 내구성이 뛰어난 데이터 저장소를 사용하려고 합니다. Redis Cache를 MongoDB 데이터베이스로 바꿉니다.
MongoDB를 사용하도록 Basket.API를 변경합니다.
- 솔루션 탐색기에서 Basket.API 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가를 선택한 다음 추가>.NET Aspire 패키지를 선택합니다.
- 검색 상자의 끝에 MongoDB를 입력하고 Enter 키를 누릅니다.
- Aspire.MongoDB.Driver를 선택한 다음 최신 8.0.0 버전을 선택합니다.
- 설치를 선택합니다.
- 변경 내용 미리 보기 대화 상자가 표시되면 적용을 선택합니다.
- 라이선스 동의 대화 상자에서 동의함을 선택합니다.@
MongoDB 장바구니 저장소 만들기
장바구니 마이크로 서비스는 HostingExtensions
를 사용하여 Redis 데이터 저장소를 관리합니다. Redis 데이터 저장소를 MongoDB 데이터 저장소로 바꿉니다.
솔루션 탐색기에서 Basket.API 프로젝트를 확장하고 Storage 폴더를 확장한 다음 RedisBasketStore.cs 파일을 선택합니다.
Redis Cache를 사용하는 두 가지 비동기 메서드(
GetBasketAsync
및UpdateBasketAsync
)가 있습니다. 이러한 메서드의 MongoDB 버전을 만들어 보겠습니다.솔루션 탐색기에서 Storage 폴더를 마우스 오른쪽 단추로 클릭한 다음 추가>클래스를 선택합니다.
새 항목 추가 대화 상자에서 파일 이름을 MongoBasketStore.cs로 지정한 다음 추가를 선택합니다.
MongoBasketStore.cs 파일의 코드를 다음 코드로 바꿉니다.
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; } }
이전 코드는
CustomerBasket
모델과 함께 작동하는MongoBasketStore
클래스를 만듭니다. 컬렉션은 MongoDB 데이터베이스에서 고객 장바구니에 대한 CRUD 작업을 처리합니다.솔루션 탐색기에서 Basket.API>확장을 확장한 다음 HostingExtensions.cs 파일을 선택합니다.
Redis 코드를 바꿉니다.
builder.AddRedis("BasketStore"); builder.Services.AddSingleton<RedisBasketStore>();
MongoDB 코드를 사용하면 다음과 같습니다.
builder.AddMongoDBClient("BasketDB"); builder.Services.AddSingleton<MongoBasketStore>();
솔루션 탐색기에서 Grpc 폴더를 확장한 다음 BasketService.cs 파일을 엽니다.
MongoBasketStore
를 허용하도록 클래스를 변경하고 다음을 바꿉니다.public class BasketService(RedisBasketStore basketStore) : Basket.BasketBase
다음으로 바꾸기:
public class BasketService(MongoBasketStore basketStore) : Basket.BasketBase
AppHost에 MongoDB 데이터베이스 추가
솔루션 탐색기에서 eShop.AppHost 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가>.NET Aspire 패키지를 선택합니다.
검색 상자의 끝에 MongoDB를 입력하고 Enter 키를 누릅니다.
Aspire.Hosting.MongoDB 패키지를 선택한 다음 최신 8.0.0 버전을 선택합니다.
설치를 선택합니다.
변경 내용 미리 보기 대화 상자가 표시되면 적용을 선택합니다.
라이선스 동의 대화 상자에서 동의함을 선택합니다.@
솔루션 탐색기에서 eShop.AppHost 프로젝트를 확장한 다음 Program.cs 파일을 엽니다.
데이터베이스 섹션에서 MongoDB 구성 요소를 추가합니다.
var mongo = builder.AddMongoDB("mongo") .WithMongoExpress() .AddDatabase("BasketDB");
이전 코드는 MongoDB 데이터베이스 컨테이너를 만들고 BasketDB라는 데이터베이스를 추가합니다. 또한 이 코드는 MongoDB 데이터베이스를 관리할 수 있는 Mongo Express 도구용 컨테이너를 만듭니다.
Redis 컨테이너를 삭제합니다.
var basketStore = builder.AddRedis("BasketStore").WithRedisCommander();
이제 코드가 다음과 같이 표시됩니다.
// 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");
Basket.API 프로젝트에는 새 MongoDB 데이터베이스에 대한 참조가 필요하며 Redis 참조를 제거해야 합니다.
var basketApi = builder.AddProject<Projects.Basket_API>("basket-api") .WithReference(mongo) .WithReference(idp);
이제 Basket.API 프로젝트가 MongoDB 데이터베이스를 사용할 준비가 되었습니다. 앱이 작동하는지 테스트해 보겠습니다.
앱 테스트
앱을 컴파일하고 시작하거나 F5를 누르거나 디버그 >디버깅 시작을 선택합니다.
대시보드에서 새로운 MongoDB 컨테이너(하나는 데이터베이스 서버용, 다른 하나는 Mongo Express용)를 볼 수 있습니다. BasketDB 데이터베이스를 호스팅하는 새 MongoDBDatabase 리소스도 있습니다.
webapp 엔드포인트를 선택합니다.
테스트 사용자 자격 증명으로 로그인하려면 오른쪽 상단에 있는 사용자 아이콘을 선택합니다. 이메일은 test@example.com이고 암호는 P@$$w0rd1입니다.
홈페이지에서 Adventurer GPS Watch를 선택합니다.
쇼핑 백에 추가를 선택하면 예외가 표시됩니다.
앱 디버그
장바구니에 항목을 추가하려고 하면 앱에서 예외가 throw됩니다. 대시보드를 사용하여 문제를 디버깅할 수 있습니다.
브라우저에서 eShop 리소스 대시보드 탭을 선택합니다.
대시보드에는 basket-api 및 webapp의 오류가 표시됩니다. basket-api에 대한 로그를 검토합니다.
basket-api 리소스의 경우 로그 열에서 보기를 선택합니다.
예외가 있습니다.
System.FormatException: Element '_id' does not match any field or property of class eShop.Basket.API.Models.CustomerBasket.
리소스 메뉴 항목을 선택한 다음 mongo-mongoexpress 엔드포인트를 선택합니다.
데이터베이스 섹션에서 BasketDB 옆에 있는 보기를 선택합니다.
컬렉션에서 장바구니 항목 옆에 있는 보기를 선택합니다.
MongoDB에 저장된 문서에는 _id 필드가 있습니다. MongoDB 컬렉션에 저장된 모든 문서에는 고유한 _id 필드가 있어야 합니다.
디버깅을 중지하려면 Shift+F5를 누르거나 디버그 > 디버깅 중지를 선택합니다.
코드 검토 및 문제 해결
CustomerBasket을 살펴보고 문제를 찾을 수 있는지 살펴보겠습니다.
솔루션 탐색기에서 Basket.API>Models 폴더를 확장한 다음 CustomerBasket.cs 파일을 엽니다.
public class CustomerBasket { public required string BuyerId { get; set; } public List<BasketItem> Items { get; set; } = []; }
CustomerBasket 모델에 _id 필드와 일치하는 필드 또는 속성이 없습니다. 엔터티 프레임워크가 _id 필드를 CustomerBasket 모델에 매핑하려고 시도하지만 일치하는 엔터티를 찾을 수 없습니다.
_id 필드를 포함하도록
CustomerBasket
모델을 업데이트합니다.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; } = []; }
수정된 앱 테스트
앱을 컴파일하고 시작하려면 F5를 누르거나 디버그 > 디버깅 시작을 선택합니다.
webapp의 경우 Endpoints 열에서 URL을 마우스 오른쪽 단추로 클릭한 다음 InPrivate 창에서 링크 열기를 선택합니다.
InPrivate 창을 사용하면 브라우저가 인증을 위해 이전 세션 쿠키를 사용하지 않습니다.
테스트 사용자 자격 증명으로 로그인하려면 오른쪽 상단에 있는 사용자 아이콘을 선택합니다. 이메일은 test@example.com이고 암호는 P@$$w0rd1입니다.
홈페이지에서 Adventurer GPS Watch를 선택합니다.
쇼핑 백에 추가를 선택합니다.
Northern Mountains 앱 바구니 기능이 이제 작동합니다.
SQLite 데이터베이스를 PostgreSQL 데이터베이스로, Redis Cache를 MongoDB 데이터베이스로 성공적으로 바꿨습니다. .NET Aspire를 사용하여 데이터베이스를 관리하고 저장된 데이터를 탐색했으며 대시보드를 사용하여 앱 문제를 디버그했습니다.