Compartilhar via


Tutorial: Desenvolver um aplicativo de console do .NET com o Azure Cosmos DB for NoSQL

APLICA-SE A: NoSQL

O SDK do Azure para .NET permite que você adicione dados a uma API para contêiner NoSQL, seja para operações individuais assíncronas ou para um lote transacional. Este tutorial mostra o passo a passo do processo de criação de um novo aplicativo de console .NET que adiciona vários itens a um contêiner.

Neste tutorial, você aprenderá a:

  • Criar um banco de dados usando a API para NoSQL
  • Criar um aplicativo de console .NET e adicionar o SDK do Azure para .NET
  • Adicionar itens individuais a um contêiner da API para NoSQL
  • Recuperar itens eficientes de um contêiner da API para NoSQL
  • Criar uma transação com alterações em lote para o contêiner da API para NoSQL

Pré-requisitos

Criar API para recursos NoSQL

Primeiro, crie um banco de dados vazio na conta existente da API para NoSQL. Você cria um contêiner usando o SDK do Azure para .NET posteriormente.

  1. Navegue até sua conta existente da API para NoSQL no portal do Azure.

  2. No menu de recursos, selecione Chaves.

    Captura de tela de uma página de conta da API para NoSQL. A opção Chaves é realçada no menu de recursos.

  3. Na página Chaves, observe e registre o valor dos campos URI e PRIMARY KEY. Esses valores são usados ao longo do tutorial.

    Captura de tela da página Chaves com os campos URI e Chave Primária realçados.

  4. No menu de recursos, selecione Data Explorer.

    Captura de tela da opção Data Explorer realçada no menu de recursos.

  5. Na página Data Explorer, selecione a opção Novo Banco de Dados na barra de comandos.

    Captura de tela da opção Novo Banco de Dados na barra de comandos Data Explorer.

  6. Na caixa de diálogo Novo Banco de Dados, crie um novo contêiner com as seguintes configurações:

    Valor
    ID do banco de dados cosmicworks
    Tipo de taxa de transferência do banco de dados Manual
    Quantidade de taxa de transferência do banco de dados 400

    Captura de tela da caixa de diálogo Novo Banco de Dados no Data Explorer com vários valores em cada campo.

  7. Selecione OK para criar o banco de dados.

Criar um aplicativo de console .NET

Agora, você cria um novo aplicativo de console .NET e importa o SDK do Azure para .NET usando a biblioteca Microsoft.Azure.Cosmos do NuGet.

  1. Abra um terminal em um diretório vazio.

  2. Criar um novo aplicativo de console usando o modelo interno console

    dotnet new console --langVersion preview
    
  3. Adicione a versão 3.31.1-preview do pacote Microsoft.Azure.Cosmos do NuGet.

    dotnet add package Microsoft.Azure.Cosmos --version 3.31.1-preview
    
  4. Além disso, adicione a versão de pré-lançamento do pacote System.CommandLine do NuGet.

    dotnet add package System.CommandLine --prerelease
    
  5. Adicione, também, o pacote Humanizer do NuGet.

    dotnet add package Humanizer
    
  6. Compile o projeto do aplicativo de console.

    dotnet build
    
  7. Abra o Visual Studio Code usando a pasta de projeto atual como o workspace.

    Dica

    Você pode executar code . no terminal para abrir o Visual Studio Code e abrir automaticamente o diretório de trabalho como o workspace atual.

  8. Navegue até o arquivo Program.cs e abra-o. Exclua todo o código existente no arquivo.

  9. Adicione esse código ao arquivo para usar a biblioteca System.CommandLine a fim de analisar a linha de comando de duas cadeias de caracteres passadas por meio das opções --first e --last.

    using System.CommandLine;
    
    var command = new RootCommand();
    
    var nameOption = new Option<string>("--name") { IsRequired = true };
    var emailOption = new Option<string>("--email");
    var stateOption = new Option<string>("--state") { IsRequired = true };
    var countryOption = new Option<string>("--country") { IsRequired = true };
    
    command.AddOption(nameOption);
    command.AddOption(emailOption);
    command.AddOption(stateOption);
    command.AddOption(countryOption);
    
    command.SetHandler(
        handle: CosmosHandler.ManageCustomerAsync, 
        nameOption, 
        emailOption,
        stateOption,
        countryOption
    );
    
    await command.InvokeAsync(args);
    

    Observação

    Para este tutorial, não é totalmente importante que você entenda como funciona o analisador de linha de comando. O analisador tem quatro opções que podem ser especificadas quando o aplicativo está em execução. Três das opções são necessárias, pois elas serão usadas para construir os campos de ID e chave de partição.

  10. Nesse ponto, o projeto não será compilado, pois você ainda não definiu o método estático CosmosHandler.ManageCustomerAsync.

  11. Salve o arquivo Program.cs.

Adicionar itens a um contêiner usando o SDK

Em seguida, você usa operações individuais para adicionar itens ao contêiner da API para NoSQL. Nesta seção, você define o método CosmosHandler.ManageCustomerAsync.

  1. Crie um arquivo CosmosHandler.cs novo.

  2. No arquivo CosmosHandler.cs, adicione uma nova diretiva using para os namespaces Humanizer e Microsoft.Azure.Cosmos.

    using Humanizer;
    using Microsoft.Azure.Cosmos;
    
  3. Crie uma nova classe estática chamada CosmosHandler.

    public static class CosmosHandler
    { }
    
  4. Apenas para validar se esse aplicativo funciona, crie uma breve implementação do método estático ManageCustomerAsync a fim de imprimir a entrada de linha de comando.

    public static async Task ManageCustomerAsync(string name, string email, string state, string country)
    {
        await Console.Out.WriteLineAsync($"Hello {name} of {state}, {country}!");
    }
    
  5. Salve o arquivo CosmosHandler.cs.

  6. De volta ao terminal, execute o aplicativo.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  7. A saída do comando deve ser uma saudação divertida.

    Hello Mica Pereira of Washington, United States!
    
  8. Volte ao arquivo CosmosHandler.cs.

  9. Na classe estática CosmosHandler, adicione um novo membro private static readonly do tipo CosmosClient chamado _client.

    private static readonly CosmosClient _client;
    
  10. Crie um novo construtor estático para a classe CosmosHandler.

    static CosmosHandler()
    { }
    
  11. No construtor, crie uma nova instância da classe CosmosClient passando dois parâmetros de cadeia de caracteres com os valores URI e PRIMARY KEY que você registrou anteriormente no laboratório. Armazene essa nova instância no membro _client.

    static CosmosHandler()
    {
        _client = new CosmosClient(
            accountEndpoint: "<uri>", 
            authKeyOrResourceToken: "<primary-key>"
        );
    }
    
  12. De volta à classe estática CosmosHandler, crie um novo método assíncrono chamado GetContainerAsync que retorna um Container.

    private static async Task<Container> GetContainerAsync()
    { }
    
  13. Para as próximas etapas, adicione esse código dentro do método GetContainerAsync.

    1. Obtenha o banco de dados cosmicworks e armazene-o em uma variável chamada database.

      Database database = _client.GetDatabase("cosmicworks");
      
    2. Crie um novo genérico List<> de valores string em uma lista de caminhos de chave de partição hierárquica e armazene-o em uma variável chamada keyPaths.

      List<string> keyPaths = new()
      {
          "/address/country",
          "/address/state"
      };
      
    3. Crie uma nova variável ContainerProperties com o nome do contêiner (customers) e a lista de caminhos de chave de partição.

      ContainerProperties properties = new(
          id: "customers",
          partitionKeyPaths: keyPaths
      );
      
    4. Use o método CreateContainerIfNotExistsAsync para fornecer as propriedades do contêiner e recuperar o contêiner. Esse método criará o contêiner de forma assíncrona, de acordo com o nome, caso ele ainda não exista no banco de dados. Retorne o resultado como a saída do método GetContainerAsync.

      return await database.CreateContainerIfNotExistsAsync(
          containerProperties: properties
      );
      
  14. Exclua todo o código dentro do método ManageCustomerAsync.

  15. Para as próximas etapas, adicione esse código dentro do método ManageCustomerAsync.

    1. Chame de forma assíncrona o método GetContainerAsync e armazene o resultado em uma variável chamada container.

      Container container = await GetContainerAsync();
      
    2. Crie uma nova variável chamada id que usa o método Kebaberize de Humanizer a fim de transformar o parâmetro do método name.

      string id = name.Kebaberize();
      

      Observação

      O método Kebaberize substituirá todos os espaços por hifens e inverterá o texto em letras minúsculas.

    3. Crie um novo item de tipo anônimo usando os parâmetros dos métodos name, state e country e a variável id. Armazene o item como uma variável chamada customer.

      var customer = new {
          id = id,
          name = name,
          address = new {
              state = state,
              country = country
          }
      };
      
    4. Use o método assíncrono CreateItemAsync do contêiner para criar um novo item no contêiner e atribuir os metadados de resposta HTTP a uma variável chamada response.

      var response = await container.CreateItemAsync(customer);
      
    5. Escreva os valores das propriedades StatusCode e RequestCharge da variável response no console. Grave, também, o valor da variável id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
      
  16. Salve o arquivo CosmosHandler.cs.

  17. De volta ao terminal, execute o aplicativo novamente.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  18. A saída do comando deve incluir um status e uma cobrança de solicitação para a operação.

    [Created]       mica-pereira    7.05 RUs
    

    Observação

    A cobrança de solicitação pode variar.

  19. Execute o aplicativo mais uma vez.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  20. Desta vez, o programa deve falhar. Se você percorrer a mensagem de erro, verá que a falha ocorreu devido a um conflito no identificador exclusivo dos itens.

    Unhandled exception: Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: Conflict (409);Reason: (
        Errors : [
          "Resource with specified id or name already exists."
        ]
    );
    

Recuperar um item usando o SDK

Agora que você criou seu primeiro item no contêiner, você pode usar o mesmo SDK para recuperar o item. Aqui, você consultará e apontará para ler o item a fim de comparar a diferença no consumo de RU (unidade de solicitação).

  1. Volte ou abra o arquivo CosmosHandler.cs.

  2. Exclua todas as linhas de código do método ManageCustomerAsync, exceto as duas primeiras linhas.

    public static async Task ManageCustomerAsync(string name, string email, string state, string country)
    {
        Container container = await GetContainerAsync();
    
        string id = name.Kebaberize();
    }
    
  3. Para as próximas etapas, adicione esse código dentro do método ManageCustomerAsync.

    1. Use o método assíncrono CreateItemAsync do contêiner para criar um novo item no contêiner e atribuir os metadados de resposta HTTP a uma variável chamada response.

      var response = await container.CreateItemAsync(customer);
      
    2. Crie uma nova cadeia de caracteres chamada sql com uma consulta SQL a fim de recuperar itens em que um filtro (@id) corresponda.

      string sql = @"
      SELECT
          *
      FROM customers c
      WHERE c.id = @id
      ";
      
    3. Crie uma variável QueryDefinition chamada query passando a cadeia de caracteres sql como o único parâmetro de consulta. Além disso, use o método flexível WithParameter para aplicar o valor da variável id ao parâmetro @id.

      var query = new QueryDefinition(
          query: sql
      )
          .WithParameter("@id", id);
      
    4. Use o método genérico GetItemQueryIterator<> e a variável query para criar um iterador que obtenha dados do Azure Cosmos DB. Armazene o iterador como uma variável chamada feed. Encapsule toda essa expressão em uma instrução using a fim de descartar o iterador posteriormente.

      using var feed = container.GetItemQueryIterator<dynamic>(
          queryDefinition: query
      );
      
    5. Chame de forma assíncrona o método ReadNextAsync da variável feed e armazene o resultado em uma variável chamada response.

      var response = await feed.ReadNextAsync();
      
    6. Escreva os valores das propriedades StatusCode e RequestCharge da variável response no console. Grave, também, o valor da variável id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
      
  4. Salve o arquivo CosmosHandler.cs.

  5. De volta ao terminal, execute o aplicativo para ler o único item usando uma consulta SQL.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  6. A saída do comando deve indicar que a consulta exigiu várias unidades de solicitação (RUs).

    [OK]    mica-pereira    2.82 RUs
    
  7. De volta ao arquivo CosmosHandler.cs, exclua todas as linhas de código do método ManageCustomerAsync novamente, exceto pelas duas primeiras linhas.

    public static async Task ManageCustomerAsync(string name, string email, string state, string country)
    {
        Container container = await GetContainerAsync();
    
        string id = name.Kebaberize();
    }
    
  8. Para as próximas etapas, adicione esse código dentro do método ManageCustomerAsync.

    1. Crie uma nova instância de PartitionKeyBuilder adicionando os parâmetros state e country como um valor de chave de partição de várias partes.

      var partitionKey = new PartitionKeyBuilder()
          .Add(country)
          .Add(state)
          .Build();
      
    2. Use o método ReadItemAsync<> do contêiner para apontar o item do contêiner usando as variáveis id e partitionKey. Armazene o resultado em uma variável chamada response.

      var response = await container.ReadItemAsync<dynamic>(
          id: id, 
          partitionKey: partitionKey
      );
      
    3. Escreva os valores das propriedades StatusCode e RequestCharge da variável response no console. Grave, também, o valor da variável id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RU");
      
  9. Salve o arquivo CosmosHandler.cs novamente.

  10. De volta ao terminal, execute o aplicativo mais uma vez a fim de apontar para ler o único item.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  11. A saída do comando deve indicar que a consulta exigiu uma única RU.

    [OK]    mica-pereira    1 RUs
    

Criar uma transação usando o SDK

Por fim, você obtém o item criado, lê esse item e cria um item relacionado diferente como parte de uma única transação usando o SDK do Azure para .NET.

  1. Volte ou abra o arquivo CosmosHandler.cs.

  2. Exclua essas linhas de código do método ManageCustomerAsync.

    var response = await container.ReadItemAsync<dynamic>(
        id: id, 
        partitionKey: partitionKey
    );
    
    Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
    
  3. Para as próximas etapas, adicione esse novo código dentro do método ManageCustomerAsync.

    1. Crie um novo item de tipo anônimo usando os parâmetros dos métodos name, state e country e a variável id. Armazene o item como uma variável chamada customerCart. Este item representa um carrinho de compras em tempo real para o cliente que esteja vazio no momento.

      var customerCart = new {
          id = $"{Guid.NewGuid()}",
          customerId = id,
          items = new string[] {},
          address = new {
              state = state,
              country = country
          }
      };
      
    2. Crie outro novo item de tipo anônimo usando os parâmetros dos métodos name, state e country e a variável id. Armazene o item como uma variável chamada customerCart. Este item representa informações de envio e contato para o cliente.

      var customerContactInfo = new {
          id = $"{id}-contact",
          customerId = id,
          email = email,
          location = $"{state}, {country}",
          address = new {
              state = state,
              country = country
          }
      };
      
    3. Crie um novo lote usando o método CreateTransactionalBatch do contêiner passando a variável partitionKey. Armazene o lote como uma variável chamada batch. Use métodos fluentes para executar as seguintes ações:

      Método Parâmetro
      ReadItem id variável de cadeia de caracteres
      CreateItem customerCart variável de tipo anônimo
      CreateItem customerContactInfo variável de tipo anônimo
      var batch = container.CreateTransactionalBatch(partitionKey)
          .ReadItem(id)
          .CreateItem(customerCart)
          .CreateItem(customerContactInfo);
      
    4. Use o método ExecuteAsync do lote para iniciar a transação. Armazene o resultado em uma variável chamada response.

      using var response = await batch.ExecuteAsync();
      
    5. Escreva os valores das propriedades StatusCode e RequestCharge da variável response no console. Grave, também, o valor da variável id.

      Console.WriteLine($"[{response.StatusCode}]\t{response.RequestCharge} RUs");
      
  4. Salve o arquivo CosmosHandler.cs novamente.

  5. De volta ao terminal, execute o aplicativo mais uma vez a fim de apontar para ler o único item.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  6. A saída do comando deve mostrar as unidades de solicitação usadas para toda a transação.

    [OK]    16.05 RUs
    

    Observação

    A cobrança de solicitação pode variar.

Validar os dados finais no Data Explorer

Para concluir tudo, você usa o Data Explorer no portal do Azure para exibir os dados e o contêiner que você criou neste tutorial.

  1. Navegue até sua conta existente da API para NoSQL no portal do Azure.

  2. No menu de recursos, selecione Data Explorer.

    Captura de tela da opção Data Explorer realçada no menu de recursos.

  3. Na página do Data Explorer, expanda o banco de dados cosmicworks e, em seguida, selecione o contêiner customers.

    Captura de tela do nó de contêiner selecionado no nó do banco de dados.

  4. Na barra de comandos, selecione Nova consulta SQL.

    Captura de tela da opção Nova Consulta SQL na barra de comandos Data Explorer.

  5. No editor de consultas, observe essa cadeia de caracteres de consulta SQL.

    SELECT * FROM c
    
  6. Selecione Executar Consulta para executar a consulta e observar os resultados.

    Captura de tela da opção Executar Consulta na barra de comandos Data Explorer.

  7. Os resultados devem incluir uma matriz JSON com três itens criados neste tutorial. Observe que todos os itens têm o mesmo valor de chave de partição hierárquica, mas campos de ID exclusivos. A saída de exemplo incluída é truncada para fins de brevidade.

    [
      {
        "id": "mica-pereira",
        "name": "Mica Pereira",
        "address": {
          "state": "Washington",
          "country": "United States"
        },
        ...
      },
      {
        "id": "33d03318-6302-4559-b5c0-f3cc643b2f38",
        "customerId": "mica-pereira",
        "items": [],
        "address": {
          "state": "Washington",
          "country": "United States"
        },
        ...
      },
      {
        "id": "mica-pereira-contact",
        "customerId": "mica-pereira",
        "email": null,
        "location": "Washington, United States",
        "address": {
          "state": "Washington",
          "country": "United States"
        },
        ...
      }
    ]
    

Limpar os recursos

Exclua os recursos criados neste artigo quando não forem mais necessários. Para fazer isso, navegue até a página da conta, selecione Data Explorer, selecione o banco de dados cosmicworks e, em seguida, selecione Excluir.