자습서: Azure Cosmos DB for NoSQL로 ASP.NET 웹 애플리케이션 개발

적용 대상: NoSQL

.NET용 Azure SDK를 사용하면 C#의 LINQ 또는 SQL 쿼리 문자열을 사용하여 API for NoSQL 컨테이너에서 데이터를 쿼리할 수 있습니다. 이 자습서에서는 자리 표시자 데이터를 사용하여 API에서 대신 쿼리하는 기존 ASP.NET 웹 애플리케이션을 업데이트하는 프로세스를 안내합니다.

이 자습서에서는 다음을 하는 방법을 알아볼 수 있습니다.

  • API for NoSQL을 사용하여 데이터베이스/컨테이너 만들기 및 채우기
  • 템플릿에서 ASP.NET 웹 애플리케이션 만들기
  • .NET용 Azure SDK를 사용하여 API for NoSQL 컨테이너의 데이터 쿼리

필수 조건

NoSQL 리소스에 대한 API 만들기

먼저 기존 API for NoSQL 계정에 데이터베이스 및 컨테이너를 만듭니다. 그런 다음, cosmicworks dotnet 도구를 사용하여 이 계정을 데이터로 채웁니다.

  1. Azure Portal 기존 API for NoSQL 계정으로 이동합니다.

  2. 리소스 메뉴에서 를 선택합니다.

    NoSQL 계정 페이지의 API 스크린샷. 키 옵션은 리소스 메뉴에서 강조 표시됩니다.

  3. 페이지에서 PRIMARY CONNECTION STRING* 필드의 값을 확인하고 기록합니다. 이 값은 자습서 전체에서 사용됩니다.

    URI, 기본 키 및 기본 연결 문자열 필드가 강조 표시된 키 페이지의 스크린샷

  4. 리소스 메뉴에서 데이터 탐색기를 선택합니다.

    리소스 메뉴에서 강조 표시된 Data Explorer 옵션의 스크린샷

  5. Data Explorer 페이지의 명령 모음에서 새 컨테이너 옵션을 선택합니다.

    Data Explorer 명령 모음의 새 컨테이너 옵션 스크린샷

  6. 새 컨테이너 대화 상자에서 다음 설정을 사용하여 새 컨테이너를 만듭니다.

    설정
    데이터베이스 ID cosmicworks
    데이터베이스 처리량 유형 수동
    데이터베이스 처리량 1000
    컨테이너 ID products
    파티션 키 /category/name

    각 필드에 다양한 값이 있는 Data Explorer 새 컨테이너 대화 상자의 스크린샷

    Important

    이 자습서에서는 먼저 공유 처리량에서 최대 1,000RU/s까지 데이터베이스를 스케일링하여 데이터 마이그레이션에 대한 성능을 최대화합니다. 데이터 마이그레이션이 완료되면 프로비저닝된 처리량 400 RU/s로 스케일링 다운합니다.

  7. 확인을 선택하여 데이터베이스와 컨테이너를 만듭니다.

  8. 터미널을 열고 명령을 실행하여 컨테이너를 데이터로 채웁니다.

    여기서 Azure Cloud Shell을 사용할 수도 있습니다.

  9. NuGet에서 cosmicworks dotnet 도구의 v2를 설치합니다.

    dotnet tool install --global cosmicworks  --version 2.*
    
  10. cosmicworks 도구를 사용하여 이 랩의 앞부분에서 기록해 둔 URI기본 키 값을 사용하여 샘플 제품 데이터로 API for NoSQL 계정을 채웁니다. 이러한 기록해 둔 값은 각각 endpointkey 매개 변수에 사용됩니다.

    cosmicworks \
        --number-of-products 1759 \
        --number-of-employees 0 \
        --disable-hierarchical-partition-keys \
        --connection-string <nosql-connection-string>
    
  11. 명령줄 도구의 출력을 확인합니다. 컨테이너에 1759개의 항목을 추가해야 합니다. 포함된 예제 출력은 간단히 나타내기 위해 잘립니다.

    ── 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
    
  12. 계정의 Data Explorer 페이지로 돌아갑니다.

  13. 데이터 섹션에서 cosmicworks 데이터베이스 노드를 확장한 다음, 스케일링을 선택합니다.

    데이터베이스 노드 내의 스케일링 옵션 스크린샷

  14. 처리량을 1,000에서 400으로 줄입니다.

    데이터베이스의 처리량 설정이 400RU/s로 축소된 스크린샷

  15. 명령 모음에서 저장을 선택합니다.

    Data Explorer 명령 모음의 저장 옵션 스크린샷

  16. 데이터 섹션에서 제품 컨테이너 노드를 확장하고 선택합니다.

    데이터베이스 노드 내에서 확장된 컨테이너 노드의 스크린샷

  17. 명령 모음에서 새 SQL 쿼리를 선택합니다.

    Data Explorer 명령 모음의 새 SQL 쿼리 옵션 스크린샷

  18. 쿼리 편집기에서 이 SQL 쿼리 문자열을 추가합니다.

    SELECT
      p.sku,
      p.price
    FROM products p
    WHERE p.price < 2000
    ORDER BY p.price DESC
    
  19. 쿼리 실행을 선택하여 쿼리를 실행하고 결과를 관찰합니다.

    Data Explorer 명령 모음의 쿼리 실행 옵션 스크린샷

  20. 결과는 최고가부터 최저가까지 정렬된 2,000보다 작은 price 값을 사용하여 컨테이너에 있는 모든 항목의 페이지 매긴 배열입니다. 간단히 하기 위해 여기에는 출력의 하위 집합이 포함됩니다.

    [
      {
        "sku": "BK-R79Y-48",
        "price": 1700.99
      },
      ...
      {
        "sku": "FR-M94B-46",
        "price": 1349.6
      },
    ...
    
  21. 쿼리 편집기의 내용을 이 쿼리로 바꾼 다음, 쿼리 실행을 다시 선택하여 결과를 확인합니다.

    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)
    
  22. 결과는 name 값이 Tag-32인 태그가 하나 이상 있는 항목만 포함하도록 필터링된 항목의 작은 배열입니다. 다시 말하지만, 간단히 하기 위해 여기에는 출력의 하위 집합이 포함됩니다.

    [
      ...
      {
        "name": "HL Touring Frame - Yellow, 60",
        "category": "Components",
        "subcategory": "Touring Frames",
        "tags": [
          "Components",
          "Touring Frames",
          "Yellow",
          "60"
        ]
      },
      ...
    ]
    

ASP.NET 웹 애플리케이션 만들기

이제 샘플 프로젝트 템플릿을 사용하여 새 ASP.NET 웹 애플리케이션을 만듭니다. 그런 다음, 소스 코드를 탐색하고 샘플을 실행하여 .NET용 Azure SDK를 사용하여 Azure Cosmos DB 연결을 추가하기 전에 애플리케이션에 익숙해지도록 합니다.

Important

이 자습서에서는 NuGet에서 패키지를 투명하게 풀합니다. dotnet nuget list source를 사용하여 패키지 원본을 확인할 수 있습니다. NuGet을 패키지 원본으로 사용하지 않는 경우 dotnet nuget add source를 사용하여 사이트를 원본으로 설치합니다.

  1. 빈 디렉터리에서 터미널을 엽니다.

  2. NuGet에서 cosmicworks.template.web 프로젝트 템플릿 패키지를 설치합니다.

    dotnet new install cosmicworks.template.web
    
  3. 새로 설치된 dotnet new cosmosdbnosql-webapp 템플릿을 사용하여 새 웹 애플리케이션 프로젝트를 만듭니다.

    dotnet new cosmosdbnosql-webapp
    
  4. 웹 애플리케이션 프로젝트를 빌드 및 실행합니다.

    dotnet run
    
  5. 실행 명령의 출력을 확인합니다. 출력에는 애플리케이션이 실행 중인 포트 및 URL 목록이 포함됩니다.

    ...
    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
    ...
    
  6. 새 브라우저를 열고 실행 중인 웹 애플리케이션으로 이동합니다. 실행 중인 애플리케이션의 세 페이지를 모두 확인합니다.

    자리 표시자 데이터로 실행되는 샘플 웹 애플리케이션의 스크린샷

  7. 실행 중인 프로세스를 종료하여 실행 중인 애플리케이션을 중지합니다.

    Ctrl+C 명령을 사용하여 실행 중인 프로세스를 중지합니다. 또는 터미널을 닫았다가 다시 열 수 있습니다.

  8. 현재 프로젝트 폴더를 작업 영역으로 사용하여 Visual Studio Code 엽니다.

    터미널에서 code .을(를) 실행하여 Visual Studio Code를 열고 자동으로 작업 디렉터리를 현재 작업 영역으로 열 수 있습니다.

  9. Services/ICosmosService.cs 파일로 이동한 후 엽니다. RetrieveActiveProductsAsyncRetrieveAllProductsAsync 기본 메서드 구현을 확인합니다. 이러한 메서드는 프로젝트를 처음 실행할 때 사용할 제품의 고정 목록을 만듭니다. 메서드 중 하나의 잘린 예제가 여기에 제공됩니다.

    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),
            ...
        };
    }
    
  10. Services/CosmosService.cs 파일로 이동한 후 엽니다. CosmosService 클래스의 현재 구현을 확인합니다. 이 클래스는 ICosmosService 인터페이스를 구현하지만 메서드를 재정의하지는 않습니다. 이 컨텍스트에서 클래스는 구현의 재정의가 인터페이스에 제공될 때까지 기본 인터페이스 구현을 사용합니다.

    public class CosmosService : ICosmosService
    { }
    
  11. 마지막으로 Models/Product.csModels/Category.cs 파일을 찾아 엽니다. 각 파일에 정의된 레코드 종류를 확인합니다. 이러한 형식은 이 자습서 전체에서 쿼리에 사용됩니다.

    public record Product(
        string id,
        Category category,
        string sku,
        string name,
        string description,
        decimal price
    );
    
    public record Category(
        string name
    );
    

.NET SDK를 사용하여 데이터 쿼리

다음으로, 이 샘플 프로젝트에 .NET용 Azure SDK를 추가하고 라이브러리를 사용하여 API for NoSQL 컨테이너의 데이터를 쿼리합니다.

  1. 터미널로 돌아가서 NuGet에서 Microsoft.Azure.Cosmos 패키지를 추가 합니다.

    dotnet add package Microsoft.Azure.Cosmos
    
  2. 프로젝트를 빌드합니다.

    dotnet build
    
  3. 다시 Visual Studio Code에서 Services/CosmosService.cs 파일로 이동합니다.

  4. Microsoft.Azure.CosmosMicrosoft.Azure.Cosmos.Linq 네임스페이스에 대한 새 using 지시문을 추가합니다.

    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    
  5. CosmosService 클래스 내에서 _client라는 CosmosClient 형식의 새 private readonly 멤버를 추가합니다.

    private readonly CosmosClient _client;
    
  6. CosmosService 클래스에 대한 빈 생성자를 새로 만듭니다.

    public CosmosService()
    { }
    
  7. 생성자 내에서 이전에 랩에서 기록해 둔 CosmosClient기본 연결 문자열 값을 사용하여 문자열 매개 변수를 전달하는 클래스의 새 인스턴스를 만듭니다. 이 새 인스턴스를 _client 멤버에 저장합니다.

    public CosmosService()
    { 
        _client = new CosmosClient(
            connectionString: "<primary-connection-string>"
        );
    }
    
  8. CosmosService 클래스 내에서 container라는 Container 형식의 새 private 속성을 만듭니다. get 접근자를 설정하여 cosmicworks 데이터베이스와 products 컨테이너를 반환합니다.

    private Container container
    {
        get => _client.GetDatabase("cosmicworks").GetContainer("products");
    }
    
  9. IEnumerable<Product>를 반환하는 RetrieveAllProductsAsync라는 새 비동기 메서드를 만듭니다.

    public async Task<IEnumerable<Product>> RetrieveAllProductsAsync()
    { }
    
  10. 다음 단계에서는 RetrieveAllProductsAsync 메서드 내에 이 코드를 추가합니다.

    1. GetItemLinqQueryable<> 제네릭 메서드를 사용하여 LINQ(언어 통합 쿼리)를 생성하는 데 사용할 수 있는 IQueryable<> 형식의 개체를 가져옵니다. 해당 개체를 queryable라는 변수에 저장합니다.

      var queryable = container.GetItemLinqQueryable<Product>();
      
    2. WhereOrderByDescending 확장 메서드를 사용하여 LINQ 쿼리를 생성합니다. ToFeedIterator 확장 메서드를 통해 반복기를 만들어 Azure Cosmos DB에서 데이터를 가져오고 feed라는 변수에 반복기를 저장합니다. 이 전체 식을 using 문으로 래핑하여 나중에 반복기를 삭제합니다.

      using FeedIterator<Product> feed = queryable
          .Where(p => p.price < 2000m)
          .OrderByDescending(p => p.price)
          .ToFeedIterator();
      
    3. 제네릭 List<> 형식을 사용하여 results라는 새 변수를 만듭니다.

      List<Product> results = new();
      
    4. feed 변수의 HasMoreResults 속성이 false를 반환할 때까지 반복되는 while 루프를 만듭니다. 이 루프는 서버 쪽 결과의 모든 페이지를 반복하도록 합니다.

      while (feed.HasMoreResults)
      { }
      
    5. while 루프 내에서 feed 변수의 ReadNextAsync 메서드를 비동기적으로 호출하고 response라는 변수에 결과를 저장합니다.

      while (feed.HasMoreResults)
      {
          var response = await feed.ReadNextAsync();
      }
      
    6. while 루프 내에서 foreach 루프를 사용하여 응답의 각 항목을 거친 후 살펴보고 results 목록에 추가합니다.

      while (feed.HasMoreResults)
      {
          var response = await feed.ReadNextAsync();
          foreach (Product item in response)
          {
              results.Add(item);
          }
      }
      
    7. results 목록을 RetrieveAllProductsAsync 메서드의 출력으로 반환합니다.

      return results;
      
  11. IEnumerable<Product>를 반환하는 RetrieveActiveProductsAsync라는 새 비동기 메서드를 만듭니다.

    public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync()
    { }
    
  12. 다음 단계에서는 RetrieveActiveProductsAsync 메서드 내에 이 코드를 추가합니다.

    1. SQL 쿼리에서 sql이라는 새 문자열을 만들어 필터(@tagFilter)가 각 항목의 tags 배열에 적용되는 여러 필드를 검색합니다.

      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)
      """;
      
    2. sql 문자열을 유일한 쿼리 매개 변수로 전달하는 이름이 query인 새 QueryDefinition 변수를 만듭니다. 또한 WithParameter fluid 메서드를 사용하여 red 값을 @tagFilter 매개 변수에 적용합니다.

      var query = new QueryDefinition(
          query: sql
      )
          .WithParameter("@tagFilter", "red");
      
    3. GetItemQueryIterator<> 제네릭 메서드와query 변수를 사용하여 Azure Cosmos DB에서 데이터를 가져오는 반복기를 만듭니다. feed 변수에 반복자를 저장합니다. 이 전체 식을 using 문으로 래핑하여 나중에 반복기를 삭제합니다.

      using FeedIterator<Product> feed = container.GetItemQueryIterator<Product>(
          queryDefinition: query
      );
      
    4. while 루프를 통해 결과의 여러 페이지를 반복하고 results라는 제네릭 List<>에 값을 저장합니다. 결과RetrieveActiveProductsAsync 메서드의 출력으로 반환합니다.

      List<Product> results = new();
      
      while (feed.HasMoreResults)
      {
          FeedResponse<Product> response = await feed.ReadNextAsync();
          foreach (Product item in response)
          {
              results.Add(item);
          }
      }
      
      return results;
      
  13. Services/CosmosClient.cs 파일을 저장합니다.

    코드가 올바른지 확실하지 않은 경우 GitHub의 샘플 코드에 대해 소스 코드를 확인할 수 있습니다.

최종 애플리케이션 유효성 검사

마지막으로 핫 다시 로드를 사용하도록 설정하고 애플리케이션을 실행합니다. 애플리케이션을 실행하면 코드가 API for NoSQL에서 데이터에 액세스할 수 있는지 확인합니다.

  1. 터미널로 돌아가 애플리케이션을 실행합니다.

    dotnet run
    
  2. run 명령의 출력에는 애플리케이션이 실행 중인 포트 및 URL 목록이 포함됩니다. 새 브라우저를 열고 실행 중인 웹 애플리케이션으로 이동합니다. 실행 중인 애플리케이션의 세 페이지를 모두 확인합니다. 이제 각 페이지에 Azure Cosmos DB의 라이브 데이터가 포함됩니다.

리소스 정리

더 이상 필요하지 않은 경우 이 문서에서 사용된 데이터베이스를 삭제합니다. 이렇게 하려면 계정 페이지로 이동하고 Data Explorer를 선택하고, cosmicworks 데이터베이스를 선택한 다음, 삭제를 선택합니다.

다음 단계

Azure Cosmos DB를 사용하여 첫 번째 .NET 웹 애플리케이션을 만들었으므로 이제 SDK를 좀 더 자세히 살펴보면서 더 많은 데이터를 가져오고, 복잡한 쿼리를 수행하고, Azure Cosmos DB for NoSQL 리소스를 관리할 수 있습니다.