랩: 수개 국어 데이터 솔루션 생성

학생 랩 매뉴얼

랩 시나리오

Microsoft Azure에서 두 개 이상의 데이터 서비스를 사용하도록 회사의 기존 소매 웹 애플리케이션을 업데이트하는 작업이 할당되었습니다. 회사의 목표는 각 애플리케이션 구성 요소에 가장 적합한 데이터 서비스를 활용하는 것입니다. 철저한 조사를 수행한 후 인벤토리 데이터베이스를 Azure SQL Database에서 Azure Cosmos DB로 마이그레이션하기로 결정했습니다. 또한 Azure Cache for Redis를 사용하여 쇼핑 카트 기능을 구현하기로 결정했습니다. 기존 애플리케이션 코드는 모듈식이므로 기존 애플리케이션에 Azure에서 호스트되는 이러한 데이터 서비스에 대한 새 공급자를 추가하려고 합니다.

목표

이 랩을 완료하면 다음을 수행할 수 있습니다.

  • Azure Portal을 사용하여 다양한 데이터베이스 서비스의 인스턴스를 만듭니다.

  • Azure SQL Database에 연결하는 C# 코드를 작성합니다.

  • Azure Cosmos DB에 연결하는 C# 코드를 작성합니다.

  • Azure Cache for Redis에 연결하는 C# 코드를 작성합니다.

랩 설정

  • 예상 시간: 90 분

지침

시작하기 전에

랩 가상 머신에 로그인

아래 자격 증명으로 Windows 10 가상기계에 등록 되어 있는지 확인합니다.

  • 사용자 이름: Admin

  • 암호: Pa55w.rd

설치된 응용 프로그램 검토

Windows 10 바탕 화면 하단에 있는 작업 표시줄을 살펴봅니다. 작업 표시줄에는 이 랩에서 사용할 응용 프로그램에 대한 아이콘이 포함되어 있습니다.

  • 마이크로소프트 에지

  • 파일 탐색기

  • Visual Studio Code

랩 파일 다운로드

  1. 작업 표시줄에서 Windows PowerShell 아이콘을 선택합니다.

  2. PowerShell 명령 프롬프트에서 현재 작업 디렉터리를 Allfiles(F):\ 경로로 변경합니다.

    cd F:
  1. 명령 프롬프트 내에서 다음 명령을 입력하고 Enter 키를 눌러 GitHub에서 호스트되는 microsoftlearning/AZ-203-DevelopingSolutionsforMicrosoftAzure 프로젝트를 Allfiles (F):\ 드라이브로 복제합니다.
    git clone --depth 1 --no-checkout https://github.com/microsoftlearning/AZ-203-DevelopingSolutionsForMicrosoftAzure.
  1. 명령 프롬프트 내에서 다음 명령을 입력하고 Enter 키를 눌러 AZ-203T03 랩을 완료하는 데 필요한 랩 파일을 체크 아웃합니다.
    git checkout master -- Allfiles/*
  1. 현재 실행 중인 Windows PowerShell 명령 프롬프트 응용 프로그램을 닫습니다.

연습 1: Azure에서 데이터베이스 리소스 만들기

작업 1: Azure Portal 열기

  1. Azure portal에 로그인합니다.(https://portal.azure.com).

  2. Azure Portal에 처음 로그인하는 경우 포털 둘러보기를 제공하는 대화 상자가 표시됩니다. 시작 하기 버튼를 선택하여 투어를 건너뜁니다.

작업 2: Azure Cache for Redis 리소스 만들기

  1. 다음과 같은 세부 정보를 사용하여 새 Azure Cache for Redis 리소스를 만듭니다.

    • DNS 이름: polyrediscache[소문자로 된 사용자 이름]

    • 새 리소스 그룹: 수개 국어 데이터

    • 위치: 미국 동부

    • 가격 계층: 기본 C0(250MB 캐시)

    참고: 랩을 진행하기 전에 Azure가 Azure Cache for Redis 인스턴스 만들기를 완료할 때까지 기다립니다. Redis Cache를 만들 때 알림을 받게 됩니다.

  2. 새로 만든 Azure Cache for Redis 리소스의 블레이드로 이동합니다.

  3. 액세스 키 창을 엽니다.

  4. 액세스 키 창에서 기본 연결 문자열(StackExchange.Redis) 필드에 값을 기록합니다.

    참고: 이 랩에서 나중에 이 값을 사용합니다.

작업 3: Azure SQL Server 리소스 만들기

  1. 다음과 같은 세부 정보를 사용하여 새 SQL Server 리소스를 만듭니다.

    • 서버 이름: polysqlsrvr[소문자로 된 사용자 이름]

    • 기존 리소스 그룹: 수개 국어 데이터

    • 서버 관리자 로그인: testuser

    • 암호: TestPa$$w0rd

    • 위치: 미국 동부

    • Azure 서비스의 서버 액세스 허용: Yes

    참고: 랩을 진행하기 전에 Azure가 SQL Server 인스턴스 만들기를 완료할 때까지 기다립니다. SQL Server가 만들어지면 알림을 받게 됩니다.

작업 4: Azure 코스모스 DB 계정 리소스 만들기

  1. 다음과 같은 세부 정보를 사용하여 새 Azure Cosmos DB 인스턴스를 만듭니다.

    • 계정 이름: polycosmos[소문자로 된 사용자 이름]

    • 기존 리소스 그룹: 수개 국어 데이터

    • API: 코어 (SQL)

    • 위치: 미국 동부

    • 지리적 중복성: 사용 금지

    • 다중 지역 쓰기: 사용 금지

    참고: 랩을 진행하기 전에 Azure가 Azure Cosmos DB 계정 만들기를 완료할 때까지 기다립니다. Azure Cosmos DB 계정이 만들어지면 알림을 받게 됩니다.

  2. 새로 만든 Azure Cosmos DB 계정 리소스의 블레이드로 이동합니다.

  3. 창을 엽니다.

  4.  창에서 기본 연결 문자열 필드의 값을 기록합니다.

    참고: 이 랩에서 나중에 이러한 값을 사용합니다.

작업 5: Azure 저장소 계정 리소스 만들기

  1. 다음과 같은 세부 정보를 사용하여 새 Azure Storage 계정을 만듭니다.

    • 스토리지 계정 이름: polystor[소문자로 된 사용자 이름]

    • 기존 리소스 그룹: 수개 국어 데이터

    • 계정 종류: 스토리지 V2(범용 v2)

    • 위치: 미국 동부

    • 복제: 로컬 중복 스토리지(LRS)

    • 성능: 표준

    • 액세스 계층(기본값): 핫

    참고: 랩을 진행하기 전에 Azure 에서 저장소 계정 만들기가 완료될 때까지 기다립니다. 스토리지 계정이 만들어지면 알림을 받게 됩니다.

복습

이 연습에서는 수개 국어 데이터 솔루션에 필요한 모든 Azure 리소스를 만들었습니다.

연습 2: 데이터베이스 및 이미지 가져오기

작업 1: 이미지 Blob 업로드

  1. 이 랩의 앞에서 만든 Azure Storage 계정의 polystor 블레이드로 이동합니다.

  2. 컨테이너 창을 엽니다.

  3. 다음 설정을 사용하여 새 컨테이너를 만듭니다.

    • 이름: 이미지

    • 공용 액세스 수준: Blob(블랍에 대한 익명 읽기 액세스만)

  4. 이미지 컨테이너로 이동합니다.

  5. 속성 창을 엽니다.

  6. 속성 창에서 URL 필드의 값을 기록합니다.

    참고: 이 랩에서 나중에 이 값을 사용합니다.

  7. 이미지 컨테이너의 블레이드로 돌아갑니다.

  8. 업로드 단추를 사용하여 랩 머신의 Allfiles (F):\Allfiles\Labs\03\Starter\Images 폴더에 있는 42개의 jpg 이미지 파일을 업로드합니다.

    참고: 파일이 이미 있는 경우 덮어쓰기 옵션을 사용하도록 설정하는 것이 좋습니다.

작업 2: SQL .bacpac 파일 업로드

  1. Azure Storage 계정의 polystor 블레이드로 돌아갑니다.

  2. 컨테이너 창을 다시 엽니다.

  3. 다음 설정을 사용하여 새 컨테이너를 만듭니다.

    • 이름: 데이터베이스

    • 공용 액세스 수준: 비공개(익명 액세스 없음)

  4. 데이터베이스 컨테이너로 이동합니다.

  5. 업로드 단추를 사용하여 랩 머신의 Allfiles (F):\Allfiles\Labs\03\Starter\ 폴더에 있는 AdventureWorks.bacpac 파일을 업로드합니다.

    참고: 파일이 이미 있는 경우 덮어쓰기 옵션을 사용하도록 설정하는 것이 좋습니다.

작업 3: SQL Database 가져오기

  1. 이 랩의 앞에서 만든 SQL Server 리소스의 polysqlsrvr* 블레이드로 이동합니다.

  2. 다음과 같은 세부 정보를 사용하여 Azure Storage 계정에서 SQL Server 인스턴스로 데이터베이스를 가져옵니다.

    • 스토리지 계정: polystor*

    • 데이터베이스 백업 Blob: databases\AdventureWorks.bacpac

    • 데이터베이스 이름: AdventureWorks

    • 서버 관리자 로그인: testuser

    • 암호: TestPa$$w0rd

    참고: 이 랩을 계속하기 전에 데이터베이스가 만들어질 때까지 기다립니다.

작업 4: 가져온 SQL Database 사용

  1. SQL Server 리소스의 polysqlsrvr 블레이드로 돌아갑니다.

  2. 방화벽 및 가상 네트워크 창을 엽니다.

  3. 허용되는 IP 주소 목록에 현재 (client) IP 주소를 추가하고 목록을 저장합니다.

  4. 최근에 가져온 SQL Database 리소스의 AdventureWorks 블레이드로 이동합니다.

  5. 연결 문자열 창을 엽니다.

  6. ADO.NET(SQL 인증) 연결 문자열의 값을 기록합니다.

  7. {your_username}{your_password}의 자리 표시자 값을 각각 testuserTestPa$$w0rd로 바꿔 기록한 연결 문자열을 업데이트합니다.

    참고: 예를 들어 연결 문자열이 원래 Server=tcp:polysqlsrvrinstructor.database.windows.net,1433;Initial Catalog=AdventureWorks;User ID={your_username};Password={your_password};였다면 업데이트된 연결 문자열은 Server=tcp:polysqlsrvrinstructor.database.windows.net,1433;Initial Catalog=AdventureWorks;User ID=testuser;Password=TestPa$$w0rd;가 됩니다.

  8. SQL Database 리소스의 AdventureWorks 블레이드로 돌아갑니다.

  9. 쿼리 편집기 창을 엽니다.

  10. 다음 자격 증명을 사용하여 로그인합니다.

    • 사용자 이름: testuser

    • 암호: TestPa$$w0rd

  11. 다음 쿼리를 실행하고 결과를 관찰합니다.

    SELECT * FROM AdventureWorks.dbo.Models
> **참고**: 이 쿼리는 웹 애플리케이션의 홈페이지에 표시 되는 모델의 목록을 반환합니다.
  1. 이 추가 쿼리를 실행하고 결과를 확인합니다.
    SELECT * FROM AdventureWorks.dbo.Products
> **참고**: 이 쿼리는 각 모델과 연결된 제품 목록을 반환합니다.

복습

이 연습에서는 웹 애플리케이션에 사용할 모든 리소스를 가져왔습니다.

연습 3: .NET Core 웹 애플리케이션 열기 및 구성

작업 1: 웹 애플리케이션 열기 및 빌드

  1. Visual Studio Code 사용하여 다음에 있는 솔루션 폴더를 엽니다. Allfiles (F):\Allfiles\Labs\03\Starter\AdventureWorks.

  2. 터미널을 사용하여 .NET Core 솔루션을 빌드합니다.

    dotnet build
> **참고**: ``dotnet 빌드`` 명령은 폴더의 모든 프로젝트를 빌드하기 전에 누락된 NuGet 패키지를 자동으로 복원합니다.
  1. 현재 터미널을 삭제합니다.

작업 2: SQL 연결 문자열 업데이트

  1. Visual Studio Code에서 AdventureWorks.Web/appsettings.json 파일을 엽니다.

  2. ConnectionStrings.AdventureWorksSqlContext 속성의 값을 이 랩의 앞에서 기록한 SQL DatabaseADO.NET(SQL 인증) 연결 문자열로 바꿉니다.

    참고: 여기에서 업데이트된 연결 문자열을 사용하는 것이 중요합니다. 포털에서 복사된 원래 연결 문자열에는 SQL Database에 연결하는 데 필요한 사용자 이름과 암호가 없습니다.

  3. Appsettings.json 파일을 저장합니다.

작업 3: Blob 기본 URL 업데이트

  1. Settings.BlobContainerUrl 속성의 값을 이 랩의 앞에서 기록한 images라는 Azure Storage Blob 컨테이너의 URL 속성으로 바꿉니다.

  2. Appsettings.json 파일을 저장합니다.

작업 4: 웹 애플리케이션 유효성 검사

  1. 터미널을 사용하여 컨텍스트를 AdventureWorks.Web 폴더로 변경합니다.
    cd .\AdventureWorks.Web\
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 실행합니다.
    dotnet run
> **참고**: ``dotnet run`` 명령은 프로젝트에 대한 변경 내용을 자동으로 빌드한 다음 디버거를 연결하지 않고 웹 애플리케이션을 시작합니다. 이 명령은 실행 중인 애플리케이션의 URL과 할당된 포트를 출력합니다.
  1. Microsoft Edge 브라우저를 엽니다.

  2. 열린 브라우저 창에서 포트 5000localhost에서 호스트되는 웹 애플리케이션으로 이동합니다.

    참고: URL은 http://localhost:5000입니다.

  3. 웹 애플리케이션에서 첫 페이지에 표시된 모델 목록을 확인합니다.

  4. Water Bottle 모델을 찾아 세부 정보 보기를 선택합니다.

  5. Water Bottle 제품 세부 정보 페이지에서 카트에 추가를 선택합니다.

  6. 체크 아웃 기능을 현재 사용하지 않도록 설정했는지 확인합니다.

    참고: 지금은 제품 페이지 기능만 구현되어 있습니다. 이 랩에서 나중에 체크 아웃 논리를 구현합니다.

  7. 웹 애플리케이션을 표시한 브라우저 창을 닫습니다.

  8. Visual Studio Code 창으로 돌아갑니다.

  9. 현재 터미널을 삭제합니다.

복습

이 연습에서는 Azure의 리소스에 연결하도록 ASP.NET Core 웹 애플리케이션을 구성했습니다.

연습 4: SQL 데이터를 Azure Cosmos DB로 마이그레이션

작업 1: 마이그레이션 프로젝트 만들기

  1. 터미널을 사용하여 AdventureWorks.Migrate라는 새 .NET 프로젝트를 동일한 이름의 폴더에 만듭니다.
    dotnet new console --name AdventureWorks.Migrate --langVersion 7.1
> **참고**: ``dotnet new`` 명령은 새 **console** 프로젝트를 같은 이름의 폴더에 만듭니다.
  1. 동일한 터미널을 사용하여 기존 AdventureWorks.Model 프로젝트에 대한 참조를 추가합니다.
    dotnet add .\AdventureWorks.Migrate\AdventureWorks.Migrate.csproj reference .\AdventureWorks.Models\AdventureWorks.Models.csproj
> **참고**: ``dotnet add reference`` 명령은 **AdventureWorks.Model** 프로젝트에 포함된 모델 클래스에 대한 참조를 추가합니다.
  1. 동일한 터미널을 사용하여 기존 AdventureWorks.Context 프로젝트에 대한 참조를 추가합니다.
    dotnet add .\AdventureWorks.Migrate\AdventureWorks.Migrate.csproj reference .\AdventureWorks.Context\AdventureWorks.Context.csproj
> **참고**: ``dotnet add reference`` 명령은 **AdventureWorks.Context** 프로젝트에 포함된 컨텍스트 클래스에 대한 참조를 추가합니다.
  1. 동일한 터미널을 사용하여 컨텍스트를 AdventureWorks.Migrate 폴더로 변경합니다.
    cd .\AdventureWorks.Migrate\
  1. 동일한 터미널을 사용하여 NuGet에서 Microsoft.EntityFrameworkCore.SqlServer의 버전 2.2.6을 가져옵니다.
    dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 2.2.6
> **참고**: ``dotnet add package`` 명령은 **NuGet**에서 **Microsoft.EntityFrameworkCore.SqlServer(https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer/2.2.6)** 패키지를 추가합니다.
  1. 동일한 터미널을 사용하여 NuGet에서 Microsoft.Azure.Cosmos의 버전 3.0.0을 가져옵니다.
    dotnet add package Microsoft.Azure.Cosmos --version 3.0.0
> **참고**: ``dotnet add package`` 명령은 **NuGet**에서 **Microsoft.Azure.Cosmos(https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.0.0)** 패키지를 추가합니다.
  1. 동일한 터미널을 사용하여 .NET Core 웹 애플리케이션을 빌드합니다.
    dotnet build
  1. 현재 터미널을 삭제합니다.

작업 2: .NET 클래스 만들기

  1. Visual Studio Code에서 AdventureWorks.Migrate/Program.cs 파일을 엽니다.

  2. Program.cs 파일의 모든 기존 코드를 삭제합니다.

  3. 애플리케이션에서 참조할 라이브러리에 대한 다음 using 지시문을 추가합니다.

    using AdventureWorks.Context;
    using AdventureWorks.Models;
    using Microsoft.Azure.Cosmos;
    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
  1. 두 개의 상수 문자열 속성과 비동기 Main 진입점 메서드를 사용하여 새 Program 클래스를 만듭니다.
    public class Program
    {
        private const string sqlDBConnectionString = "";
        private const string cosmosDBConnectionString = "";
        
        public static async Task Main(string[] args)
        {
        }
    }
  1. 이 랩의 앞에서 기록한 SQL DatabaseADO.NET(SQL 인증) 연결 문자열에 해당 값을 설정하여 sqlDBConnectionString 문자열 상수를 업데이트합니다.

    참고: 여기에서 업데이트된 연결 문자열을 사용하는 것이 중요합니다. 포털에서 복사된 원래 연결 문자열에는 SQL Database에 연결하는 데 필요한 사용자 이름과 암호가 없습니다.

  2. 이 랩의 앞에서 기록한 Azure Cosmos DB 계정기본 연결 문자열로 값을 설정하여 cosmosDBConnectionString 문자열 상수를 업데이트합니다.

작업 3: Entity Framework를 사용하여 SQL Database 레코드 가져오기

  1. Main 메서드 내에서 다음 코드 블록을 추가하여 Azure SQL Database에서 로컬 메모리로 모든 모델 및 제품 레코드 내보내기를 구현합니다.
    await Console.Out.WriteLineAsync("Start Migration");

    AdventureWorksSqlContext context = new AdventureWorksSqlContext(sqlDBConnectionString);

    List<Model> items = await context.Models
        .Include(m => m.Products)
        .ToListAsync<Model>();

    await Console.Out.WriteLineAsync($"Total Azure SQL DB Records: {items.Count}");
  1. Program.cs 파일을 저장합니다.

  2. 터미널을 사용하여 컨텍스트를 AdventureWorks.Migrate 폴더로 변경합니다.

    cd .\AdventureWorks.Migrate\
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 빌드합니다.
    dotnet build
> **참고**: 빌드 오류가 있는 경우 **Allfiles (F):\\Allfiles\\Labs\\03\\Solution\\AdventureWorks\\AdventureWorks.Migrate** 폴더에 있는 **Program.cs** 파일을 검토하십시오.
  1. 현재 터미널을 삭제합니다.

작업 4: Azure Cosmos DB에 항목 삽입

  1. Main 메서드 내에서 다음 코드 블록을 추가하여 Azure Cosmos DB에 문서로 메모리 내 모델 및 제품 데이터 가져오기를 구현합니다.
    CosmosClient client = new CosmosClient(cosmosDBConnectionString);

    Database database = await client.CreateDatabaseIfNotExistsAsync("Retail");

    Container container = await database.CreateContainerIfNotExistsAsync("Online",
        partitionKeyPath: $"/{nameof(Model.Category)}",
        throughput: 1000
    );

    int count = 0;
    foreach (var item in items)
    {
        ItemResponse<Model> document = await container.UpsertItemAsync<Model>(item);
        await Console.Out.WriteLineAsync($"Upserted document #{++count:000} [Activity Id: {document.ActivityId}]");
    }

    await Console.Out.WriteLineAsync($"Total Azure Cosmos DB Documents: {count}");
  1. Program.cs 파일을 저장합니다.

  2. 터미널을 사용하여 컨텍스트를 AdventureWorks.Migrate 폴더로 변경합니다.

    cd .\AdventureWorks.Migrate\
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 빌드합니다.
    dotnet build
> **참고**: 빌드 오류가 있는 경우 **Allfiles (F):\\Allfiles\\Labs\\03\\Solution\\AdventureWorks\\AdventureWorks.Migrate** 폴더에 있는 **Program.cs** 파일을 검토하십시오.

작업 5: 마이그레이션

  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 실행합니다.
    dotnet run
> **참고**: ``dotnet run`` 명령은 콘솔 애플리케이션을 시작합니다.
  1. 초기 SQL 레코드 수, 개별 upsert 활동 식별자, 최종 Azure Cosmos DB 문서 수를 비롯하여 화면에 출력되는 다양한 데이터를 확인합니다.

  2. 현재 터미널을 삭제합니다.

작업 6: 마이그레이션 유효성 검사

  1. Azure Portal을 표시한 Microsoft Edge 브라우저 창으로 돌아갑니다.

  2. 이 랩의 앞에서 만든 Azure Cosmos DB 계정의 polycosmos* 블레이드로 이동합니다.

  3. 쿼리 탐색기 창을 엽니다.

  4. Retail 데이터베이스 및 Online 컨테이너의 컨텍스트 내에서 새 SQL 쿼리 탭을 만듭니다.

  5. 다음 쿼리를 실행하고 결과를 관찰합니다.

    SELECT * FROM models
  1. 다음 쿼리를 실행하고 결과를 관찰합니다.
    SELECT VALUE COUNT(1) FROM models

복습

이 연습에서는 Entity Framework 및 Azure Cosmos DB용 .NET SDK를 사용하여 Azure SQL Database에서 Azure Cosmos DB로 데이터를 마이그레이션했습니다.

연습 5: .NET을 사용한 Azure Cosmos DB 액세스

작업 1: Cosmos SDK 및 참조를 사용하여 라이브러리 업데이트

  1. 터미널을 사용하여 컨텍스트를 AdventureWorks.Context 폴더로 변경합니다.
    cd .\AdventureWorks.Context\
  1. 동일한 터미널을 사용하여 NuGet에서 Microsoft.Azure.Cosmos를 가져옵니다.
    dotnet add package Microsoft.Azure.Cosmos --version 3.0.0
> **참고**: ``dotnet add package`` 명령은 **NuGet**에서 **Microsoft.Azure.Cosmos(https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.0.0)** 패키지를 추가합니다.
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 빌드합니다.
    dotnet build
  1. 현재 터미널을 삭제합니다.

작업 2: Azure Cosmos DB에 연결하는 .NET 코드 작성

  1. Visual Studio Code에서 새 AdventureWorks.Context/AdventureWorksCosmosContext.cs 파일 만들기

  2. 애플리케이션에서 참조할 라이브러리에 대한 다음 using 지시문을 추가합니다.

    using AdventureWorks.Models;
    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
  1. 다음 코드를 입력하여 AdventureWorks.Context 네임스페이스 블록을 추가합니다.
    namespace AdventureWorks.Context
    {
    }
  1. 단일 읽기 전용 Container 변수를 사용하여 IAdventureWorksProductContext 인터페이스를 구현하는 새 AdventureWorksCosmosContext 클래스를 만듭니다.
    public class AdventureWorksCosmosContext : IAdventureWorksProductContext
    {
        private readonly Container _container;
    }
  1. AdventureWorksCosmosContext 클래스 내에서 CosmosClient 클래스의 새 인스턴스를 만드는 새 생성자를 추가한 다음 클라이언트에서 DatabaseContainer 인스턴스를 모두 가져옵니다.
    public AdventureWorksCosmosContext(string connectionString, string database = "Retail", string container = "Online")
    {
        _container = new CosmosClient(connectionString)
            .GetDatabase(database)
            .GetContainer(container);
    }
  1. AdventureWorksCosmosContext 클래스 내에서 LINQ 쿼리를 만들고, 이를 반복기로 변환하고, 결과 집합을 반복한 다음, 결과 집합에서 단일 항목을 반환하는 새 FindModelAsync 메서드를 추가합니다.
    public async Task<Model> FindModelAsync(Guid id)
    {
        var iterator = _container.GetItemLinqQueryable<Model>()
            .Where(m => m.id == id)
            .ToFeedIterator<Model>();

        List<Model> matches = new List<Model>();
        while (iterator.HasMoreResults)
        {
            var next = await iterator.ReadNextAsync();
            matches.AddRange(next);
        }

        return matches.SingleOrDefault();
    }
  1. AdventureWorksCosmosContext 클래스 내에서 SQL 쿼리를 실행하고, 쿼리 결과 반복기를 가져오고, 결과 집합을 반복한 다음, 모든 결과의 공용 구조체를 반환하는 새 GetModelsAsync 메서드를 추가합니다.
    public async Task<List<Model>> GetModelsAsync()
    {
        string query = $@"SELECT * FROM items";

        var iterator = _container.GetItemQueryIterator<Model>(query);

        List<Model> matches = new List<Model>();
        while (iterator.HasMoreResults)
        {
            var next = await iterator.ReadNextAsync();
            matches.AddRange(next);
        }

        return matches;
    }
  1. AdventureWorksCosmosContext 클래스 내에서 SQL 쿼리를 실행하고, 쿼리 결과 반복기를 가져오고, 결과 집합을 반복한 다음, 결과 집합의 단일 항목을 반환하는 새 FindProductAsync 메서드를 추가합니다.
    public async Task<Product> FindProductAsync(Guid id)
    {
        string query = $@"SELECT VALUE products
                            FROM models
                            JOIN products in models.Products
                            WHERE products.id = '{id}'";

        var iterator = _container.GetItemQueryIterator<Product>(query);

        List<Product> matches = new List<Product>();
        while (iterator.HasMoreResults)
        {
            var next = await iterator.ReadNextAsync();
            matches.AddRange(next);
        }

        return matches.SingleOrDefault();
    }
  1. AdventureWorksCosmosContext.cs 파일을 저장합니다.

  2. 터미널을 사용하여 컨텍스트를 AdventureWorks.Context 폴더로 변경합니다.

    cd .\AdventureWorks.Context\
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 빌드합니다.
    dotnet build
> **참고**: 빌드 오류가 있는 경우 **Allfiles (F):\\Allfiles\\Labs\\03\\Solution\\AdventureWorks\\AdventureWorks.Context** 폴더에 있는 **AdventureWorksCosmosContext.cs** 파일을 검토하십시오.
  1. 현재 터미널을 삭제합니다.

작업 3: Azure Cosmos DB 연결 문자열 업데이트

  1. Visual Studio Code에서 AdventureWorks.Web/appsettings.json 파일을 엽니다.

  2. ConnectionStrings.AdventureWorksCosmosContext 속성의 값을 이 랩의 앞에서 기록한 Azure Cosmos DB 계정기본 연결 문자열로 바꿉니다.

  3. Appsettings.json 파일을 저장합니다.

작업 4: .NET 애플리케이션 시작 논리 업데이트

  1. Visual Studio Code에서 AdventureWorks.Web/Startup.cs 파일을 엽니다.

  2. Startup 클래스에서 기존 ConfigureProductService 메서드를 찾습니다.

    참고: 현재 제품 서비스는 SQL을 데이터베이스로 사용합니다.

  3. ConfigureProductService 메서드 구현을 다음 코드로 바꿉니다.

    public void ConfigureProductService(IServiceCollection services)
    {
        services.AddScoped<IAdventureWorksProductContext, AdventureWorksCosmosContext>(provider =>
                new AdventureWorksCosmosContext(
                    _configuration.GetConnectionString(nameof(AdventureWorksCosmosContext))
                )
        );
    }
  1. Startup.cs 파일을 저장합니다.

작업 5: Azure Cosmos DB에 연결된 .NET 애플리케이션 유효성 검사

  1. 터미널을 사용하여 컨텍스트를 AdventureWorks.Web 폴더로 변경합니다.
    cd .\AdventureWorks.Web\
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 실행합니다.
    dotnet run
> **참고**: ``dotnet run`` 명령은 프로젝트에 대한 변경 내용을 자동으로 빌드한 다음 디버거를 연결하지 않고 웹 애플리케이션을 시작합니다. 이 명령은 실행 중인 애플리케이션의 URL과 할당된 포트를 출력합니다.
  1. Microsoft Edge 브라우저를 엽니다.

  2. 열린 브라우저 창에서 포트 5000localhost에서 호스트되는 웹 애플리케이션으로 이동합니다.

    참고: URL은 http://localhost:5000입니다.

  3. 웹 애플리케이션에서 첫 페이지에 표시된 모델 목록을 확인합니다.

  4. Touring-1000 모델을 찾아 세부 정보 보기를 선택합니다.

  5. Touring-1000 제품 세부 정보 페이지에서 다음 작업을 수행합니다.

    1. 옵션 선택 목록에서 Touring-1000 Yellow, 50, $2,384.07을 선택합니다.

    2. 카트에 추가를 선택합니다.

  6. 체크 아웃 기능을 여전히 사용하지 않도록 설정했는지 확인합니다.

    참고: 다음 연습에서는 체크 아웃 논리를 구현합니다.

  7. 웹 애플리케이션을 표시한 브라우저 창을 닫습니다.

  8. Visual Studio Code 창으로 돌아갑니다.

  9. 현재 터미널을 삭제합니다.

복습

이 연습에서는 .NET SDK를 사용하여 Azure Cosmos DB 컬렉션을 쿼리하는 C# 코드를 작성했습니다.

연습 6: .NET을 사용하여 Azure Cache for Redis 액세스

작업 1: StackExchange.Redis SDK 및 참조를 사용하여 라이브러리 업데이트

  1. 터미널을 사용하여 컨텍스트를 AdventureWorks.Context 폴더로 변경합니다.
    cd .\AdventureWorks.Context\
  1. 동일한 터미널을 사용하여 NuGet에서 Newtonsoft.Json을 가져옵니다.
    dotnet add package Newtonsoft.Json --version 12.0.2
> **참고**: ``dotnet add package`` 명령은 **NuGet**에서 **Newtonsoft.Json(https://www.nuget.org/packages/Newtonsoft.Json/12.0.2)** 패키지를 추가합니다.
  1. 동일한 터미널을 사용하여 NuGet에서 StackExchange.Redis를 가져옵니다.
    dotnet add package StackExchange.Redis --version 2.0.601
> **참고**: ``dotnet add package`` 명령은 **NuGet**에서 **StackExchange.Redis(https://www.nuget.org/packages/StackExchange.Redis/2.0.601)** 패키지를 추가합니다.
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 빌드합니다.
    dotnet build
  1. 현재 터미널을 삭제합니다.

작업 2: Azure Cache for Redis에 연결하는 .NET 코드 작성

  1. Visual Studio Code에서 새 AdventureWorks.Context/AdventureWorksRedisContext.cs 파일을 만듭니다.

  2. 애플리케이션에서 참조할 라이브러리에 대한 다음 using 지시문을 추가합니다.

    using AdventureWorks.Models;
    using Newtonsoft.Json;
    using StackExchange.Redis;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
  1. 다음 코드를 입력하여 AdventureWorks.Context 네임스페이스 블록을 추가합니다.
    namespace AdventureWorks.Context
    {
    }
  1. 단일 읽기 전용 IDatabase 변수를 사용하여 IAdventureWorksCheckoutContext 인터페이스를 구현하는 새 AdventureWorksRedisContext 클래스를 만듭니다.
    public class AdventureWorksRedisContext : IAdventureWorksCheckoutContext
    {
        private readonly IDatabase _database;
    }
  1. AdventureWorksRedisContext 클래스 내에서 ConnectionMultiplexer 클래스의 새 인스턴스를 만드는 새 생성자를 추가한 다음 데이터베이스 인스턴스를 모두 가져옵니다.
    public AdventureWorksRedisContext(string connectionString)
    {        
        ConnectionMultiplexer connection = ConnectionMultiplexer.Connect(connectionString);
        _database = connection.GetDatabase();
    }
  1. AdventureWorksRedisContext 클래스 내에서 특정 키의 현재 값을 가져오고, 아직 없는 경우 새 목록을 만들고, 목록에 제품을 추가한 다음, 해당 키의 새 값으로 목록을 데이터베이스에 저장하는 새 AddProductToCartAsync 메서드를 추가합니다.
    public async Task AddProductToCartAsync(string uniqueIdentifier, Product product)
    {     
        RedisValue result = await _database.StringGetAsync(uniqueIdentifier);
        List<Product> products = new List<Product>();
        if (!result.IsNullOrEmpty)
        {
            List<Product> parsed = JsonConvert.DeserializeObject<List<Product>>(result.ToString());
            products.AddRange(parsed);
        }
        products.Add(product);
        string json = JsonConvert.SerializeObject(products);
        await _database.StringSetAsync(uniqueIdentifier, json);   
    }
  1. AdventureWorksRedisContext 클래스 내에서, 데이터베이스에서 목록을 가져오는 새 GetProductsInCartAsync 메서드를 추가하고 JSON 값을 Product 인스턴스 컬렉션으로 구문 분석합니다.
    public async Task<List<Product>> GetProductsInCartAsync(string uniqueIdentifier)
    {     
        string json = await _database.StringGetAsync(uniqueIdentifier);
        List<Product> products = JsonConvert.DeserializeObject<List<Product>>(json ?? "[]");
        return products;   
    }
  1. AdventureWorksRedisContext 클래스 내에서, 데이터베이스에서 키와 관련 값을 제거하는 새 ClearCart 메서드를 추가합니다.
    public async Task ClearCart(string uniqueIdentifier)
    {   
        await _database.KeyDeleteAsync(uniqueIdentifier);     
    }
  1. AdventureWorksRedisContext.cs 파일을 저장합니다.

  2. 터미널을 사용하여 컨텍스트를 AdventureWorks.Context 폴더로 변경합니다.

    cd .\AdventureWorks.Context\
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 빌드합니다.
    dotnet build
> **참고**: 빌드 오류가 있는 경우 **Allfiles (F):\\Allfiles\\Labs\\03\\Solution\\AdventureWorks\\AdventureWorks.Context** 폴더에 있는 **AdventureWorksRedisContext.cs** 파일을 검토하십시오.
  1. 현재 터미널을 삭제합니다.

작업 3: Redis 연결 문자열 업데이트

  1. Visual Studio Code에서 AdventureWorks.Web/appsettings.json 파일을 엽니다.

  2. ConnectionStrings.AdventureWorksRedisContext 속성의 값을 이 랩의 앞에서 기록한 Azure Cache for Redis 인스턴스의 기본 연결 문자열(StackExchange.Redis)로 바꿉니다.

  3. Settings.CartAvailable 속성의 기존 false 값을 새 값 true로 바꿉니다.

  4. Appsettings.json 파일을 저장합니다.

작업 4: .NET 애플리케이션 시작 논리 업데이트

  1. Visual Studio Code에서 AdventureWorks.Web/Startup.cs 파일을 엽니다.

  2. Startup 클래스에서 기존 ConfigureCheckoutService 메서드를 찾습니다.

    참고: 현재 제품 서비스는 SQL을 데이터베이스로 사용합니다.

  3. ConfigureCheckoutService 메서드 구현을 다음 코드로 바꿉니다.

    public void ConfigureCheckoutService(IServiceCollection services)
    {
        services.AddScoped<IAdventureWorksCheckoutContext, AdventureWorksRedisContext>(provider =>
            new AdventureWorksRedisContext(
                _configuration.GetConnectionString(nameof(AdventureWorksRedisContext))
            )
        );
    }
  1. Startup.cs 파일을 저장합니다.

작업 5: Azure Cache for Redis에 연결된 .NET 애플리케이션 유효성 검사

  1. 터미널을 사용하여 컨텍스트를 AdventureWorks.Web 폴더로 변경합니다.
    cd .\AdventureWorks.Web\
  1. 동일한 터미널을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 실행합니다.
    dotnet run
> **참고**: ``dotnet run`` 명령은 프로젝트에 대한 변경 내용을 자동으로 빌드한 다음 디버거를 연결하지 않고 웹 애플리케이션을 시작합니다. 이 명령은 실행 중인 애플리케이션의 URL과 할당된 포트를 출력합니다.
  1. Microsoft Edge 브라우저를 엽니다.

  2. 열린 브라우저 창에서 첫 페이지에 표시된 모델 목록을 확인합니다.

  3. Mountain-400-W 모델을 찾아 세부 정보 보기를 선택합니다.

  4. Mountain-400-W 제품 세부 정보 페이지에서 다음 작업을 수행합니다.

    1. 옵션 선택 목록에서 Mountain-400-W Silver, 40, $769.49를 선택합니다.

    2. 카트에 추가를 선택합니다.

  5. 쇼핑 카트 페이지에서 쇼핑 카트의 내용을 확인한 다음 체크 아웃을 선택합니다.

  6. 체크아웃 페이지에서 최종 영수증을 확인합니다.

  7. 페이지 상단의 쇼핑 카트 아이콘을 선택합니다.

  8. 쇼핑 카트 페이지에서 빈 카트를 확인합니다.

  9. 웹 애플리케이션을 표시한 브라우저 창을 닫습니다.

  10. Visual Studio Code 창으로 돌아갑니다.

  11. 현재 터미널을 삭제합니다.

복습

이 연습에서는 C# 코드를 사용하여 Azure Cache for Redis 스토리지에서 데이터를 저장하고 검색했습니다.

연습 7: 구독 정리

작업 1: Azure 클라우드 셸 열기

  1. Azure 포털 상단에서 Cloud Shell 아이콘을 클릭하여 새 셸 인스턴스를 엽니다.

  2. Cloud Shell이 아직 구성되지 않은 경우 기본 설정을 사용하여 Bash용 셸을 구성합니다.

  3. 포털 하단의 Cloud Shell 명령 프롬프트에서 다음 명령을 입력하고 Enter 키를 눌러 구독의 모든 리소스 그룹을 나열합니다.

    az group list
  1. 다음 명령을 입력하고 Enter 키를 눌러 리소스 그룹을 삭제하는 데 사용할 수 있는 명령 목록을 봅니다.
    az group delete --help

작업 2: 리소스 그룹 삭제

  1. 다음 명령을 입력하고 Enter 를 눌러 PolyglotData 리소스 그룹을 삭제합니다.
    az group delete --name PolyglotData --no-wait --yes
  1. 포털 하단의 Cloud Shell 창을 닫습니다.

작업 3: 활성 애플리케이션 닫기

  1. 현재 실행 중인 Microsoft Edge 응용 프로그램을 닫습니다.

  2. 현재 실행 중인 Visual Studio Code 응용 프로그램을 닫습니다.

검토

이 연습에서는 이 랩에 사용된 리소스 그룹을 제거하여 구독을 정리했습니다.