Tutorial: Desarrollo de una aplicación de consola de .NET con Azure Cosmos DB for NoSQL

SE APLICA A: NoSQL

El SDK de Azure para .NET permite agregar datos a una API para contenedor NoSQL, ya sean operaciones individuales asincrónicas o un lote transaccional. Este tutorial le guiará por el proceso de creación de una nueva aplicación de consola de .NET que agrega varios elementos a un contenedor.

En este tutorial, aprenderá a:

  • Creación de una base de datos mediante la API for NoSQL
  • Creación de una aplicación de consola de .NET y adición de Azure SDK para .NET
  • Adición de elementos individuales a un contenedor de API for NoSQL
  • Recuperación eficaz de elementos desde un contenedor de API for NoSQL
  • Creación de una transacción con cambios por lotes para el contenedor de API for NoSQL

Requisitos previos

Creación de recursos de API for NoSQL

En primer lugar, cree una base de datos vacía en la cuenta de API for NoSQL. Más adelante, creará un contenedor mediante Azure SDK para .NET.

  1. Vaya a la cuenta de API for NoSQL en Azure Portal.

  2. En el menú de recursos, seleccione Registros.

    Screenshot of an API for NoSQL account page. The Keys option is highlighted in the resource menu.

  3. En la página Claves, compruebe y anote el valor de los campos URI y PRIMARY KEY. Estos valores se usarán a lo largo del tutorial.

    Screenshot of the Keys page with the URI and Primary Key fields highlighted.

  4. En el menú de recursos, seleccione Explorador de datos.

    Screenshot of the Data Explorer option highlighted in the resource menu.

  5. En la página de Data Explorer, seleccione la opción Nueva base de datos en la barra de comandos.

    Screenshot of the New Database option in the Data Explorer command bar.

  6. En el cuadro de diálogo Nueva base de datos, cree un contenedor con esta configuración:

    Value
    Id. de base de datos cosmicworks
    Tipo de rendimiento de la base de datos Manual
    Cantidad de rendimiento de la base de datos 400

    Screenshot of the New Database dialog in the Data Explorer with various values in each field.

  7. Para crear la base de datos, seleccione Aceptar.

Creación de una aplicación de consola de .NET

Ahora, creará una nueva aplicación de consola de .NET e importará Azure SDK para .NET mediante la biblioteca Microsoft.Azure.Cosmos de NuGet.

  1. Abra un terminal en un directorio vacío.

  2. Creación de una nueva aplicación de consola mediante la plantilla integrada console

    dotnet new console --langVersion preview
    
  3. Agregue la versión 3.31.1-preview del paquete Microsoft.Azure.Cosmos de NuGet.

    dotnet add package Microsoft.Azure.Cosmos --version 3.31.1-preview
    
  4. Agregue también la versión preliminar del paquete System.CommandLine De NuGet.

    dotnet add package System.CommandLine --prerelease
    
  5. Agregue también el paquete Humanizer de NuGet.

    dotnet add package Humanizer
    
  6. Compile el proyecto de la aplicación de consola.

    dotnet build
    
  7. Abra Visual Studio Code mediante la carpeta del proyecto actual como área de trabajo.

    Sugerencia

    Puede ejecutar code . en el terminal para abrir Visual Studio Code e iniciar automáticamente el directorio de trabajo como área de trabajo actual.

  8. Vaya al archivo Program.cs y ábralo. Elimine el código existente del archivo.

  9. Agregue este código al archivo para usar la biblioteca System.CommandLine y analizar la línea de comandos para dos cadenas transferidas a través de las opciones --first y --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);
    

    Nota:

    Para este tutorial, no es fundamental conocer el funcionamiento del analizador de línea de comandos. El analizador tiene cuatro opciones que se pueden especificar cuando se ejecuta la aplicación. Tres de las opciones son necesarias, ya que se usarán para generar los campos de id. y clave de partición.

  10. En este punto, el proyecto no se compilará, ya que aún no se ha definido el método estático CosmosHandler.ManageCustomerAsync.

  11. Guarde el archivo Program.cs.

Adición de elementos a un contenedor mediante el SDK

A continuación, usará operaciones individuales para agregar elementos al contenedor de API for NoSQL. En esta sección, se definirá el método CosmosHandler.ManageCustomerAsync.

  1. Cree un nuevo archivo CosmosHandler.cs.

  2. En el archivo CosmosHandler.cs, agregue una nueva directiva con los espacios de nombres Humanizer y Microsoft.Azure.Cosmos.

    using Humanizer;
    using Microsoft.Azure.Cosmos;
    
  3. Cree un nuevo método estático denominado CosmosHandler.

    public static class CosmosHandler
    { }
    
  4. Con el fin de comprobar que la aplicación funcionará, cree una breve implementación del método estático ManageCustomerAsync para imprimir la entrada de la línea de comandos.

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

  6. De nuevo en el terminal, ejecute la aplicación.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  7. La salida del comando debe ser un saludo divertido.

    Hello Mica Pereira of Washington, United States!
    
  8. Vuelva al archivo CosmosHandler.cs.

  9. En la clase estática CosmosHandler, agregue un nuevo miembro private static readonly del tipo CosmosClient denominado _client.

    private static readonly CosmosClient _client;
    
  10. Cree un nuevo constructor estático para la clase CosmosHandler.

    static CosmosHandler()
    { }
    
  11. En el constructor, cree una nueva instancia de la clase CosmosClient pasando dos parámetros de cadena con los valores URI y PRIMARY KEY que registró anteriormente en el laboratorio. Almacene esta nueva instancia en el miembro _client.

    static CosmosHandler()
    {
        _client = new CosmosClient(
            accountEndpoint: "<uri>", 
            authKeyOrResourceToken: "<primary-key>"
        );
    }
    
  12. De nuevo dentro de la clase estática CosmosHandler, cree un nuevo método asincrónico denominado GetContainerAsync que devuelva un valor Container.

    private static async Task<Container> GetContainer()
    { }
    
  13. Para los pasos siguientes, agregue este código dentro del método GetContainerAsync.

    1. Obtenga la base de datos cosmicworks y almacénela en una variable denominada database.

      Database database = _client.GetDatabase("cosmicworks");
      
    2. Cree una nueva variable List<> genérica de valores string en una lista de rutas de acceso de clave de partición jerárquica y almacénela en una variable denominada keyPaths.

      List<string> keyPaths = new()
      {
          "/address/country",
          "/address/state"
      };
      
    3. Cree una nueva variable ContainerProperties con el nombre del contenedor (customers) y la lista de rutas de acceso de clave de partición.

      ContainerProperties properties = new(
          id: "customers",
          partitionKeyPaths: keyPaths
      );
      
    4. Use el método CreateContainerIfNotExistsAsync para proporcionar las propiedades del contenedor y recuperar este. En función del nombre, este método creará de forma asincrónica el contenedor si aún no existe en la base de datos. Obtenga el resultado como la salida del método GetContainerAsync.

      return await database.CreateContainerIfNotExistsAsync(
          containerProperties: properties
      );
      
  14. Elimine todo el código del método ManageCustomerAsync.

  15. Para los pasos siguientes, agregue este código dentro del método ManageCustomerAsync.

    1. Llame de forma asincrónica al método GetContainerAsync y almacene el resultado en una variable denominada container.

      Container container = await GetContainerAsync();
      
    2. Cree una variable denominada id que use el método Kebaberize de Humanizer para transformar el parámetro de método name.

      string id = name.Kebaberize();
      

      Nota

      El método Kebaberize reemplazará todos los espacios por guiones y cambiará el texto a minúsculas.

    3. Cree un nuevo elemento con tipo anónimo mediante los parámetros de método name, statey country, junto con la variable id. Almacene el elemento como una variable denominada customer.

      var customer = new {
          id = id,
          name = name,
          address = new {
              state = state,
              country = country
          }
      };
      
    4. Use el método asincrónico CreateItemAsync del contenedor para crear un nuevo elemento en el contenedor y asignar los metadatos de respuesta HTTP a una variable denominada response.

      var response = await container.CreateItemAsync(customer);
      
    5. Escriba los valores de las propiedades StatusCode y RequestCharge de la variable response en la consola. Escriba también el valor de la variable id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
      
  16. Guarde el archivo CosmosHandler.cs.

  17. De nuevo en el terminal, vuelva a ejecutar la aplicación.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  18. La salida del comando deberá incluir un estado y un cargo asociado a la solicitud para la operación.

    [Created]       mica-pereira    7.05 RUs
    

    Nota

    El cargo asociado a la solicitud puede variar.

  19. Ejecute la aplicación una vez más.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  20. Esta vez, el programa debería bloquearse. Si se desplaza por el mensaje de error, verá que el bloqueo se produjo debido a un conflicto en el identificador único de los elementos.

    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."
        ]
    );
    

Recuperación de un elemento mediante el SDK

Una vez que se ha creado el primer elemento en el contenedor, podrá usar el mismo SDK para recuperar el elemento. Consulte aquí el elemento para comparar la diferencia en el consumo de unidades de solicitud (RU).

  1. Vuelva al archivo CosmosHandler.cs o ábralo.

  2. Elimine todas las líneas de código del método ManageCustomerAsync, salvo por las dos primeras líneas.

    public static async Task ManageCustomerAsync(string name, string email, string state, string country)
    {
        Container container = await GetContainerAsync();
    
        string id = name.Kebaberize();
    }
    
  3. Para los pasos siguientes, agregue este código dentro del método ManageCustomerAsync.

    1. Use el método asincrónico CreateItemAsync del contenedor para crear un nuevo elemento en el contenedor y asignar los metadatos de respuesta HTTP a una variable denominada response.

      var response = await container.CreateItemAsync(customer);
      
    2. Cree una nueva cadena denominada sql con una consulta SQL para recuperar elementos en los que coincida un filtro (@id).

      string sql = """
      SELECT
          *
      FROM customers c
      WHERE c.id = @id
      """;
      
    3. Cree una nueva variable QueryDefinition denominada query que pase la cadena sql como el único parámetro de consulta. Además, use el método fluid WithParameter para aplicar el valor de la variable id al parámetro @id.

      var query = new QueryDefinition(
          query: sql
      )
          .WithParameter("@id", id);
      
    4. Use el método genérico GetItemQueryIterator<> y la variable query para crear un iterador que obtenga datos de Azure Cosmos DB. Almacene el elemento como una variable denominada feed. Encapsule esta expresión completa en una instrucción using para desechar el iterador más adelante.

      using var feed = container.GetItemQueryIterator<dynamic>(
          queryDefinition: query
      );
      
    5. Llame de forma asincrónica al método ReadNextAsync de la variable feed y almacene el resultado en una variable denominada response.

      var response = await feed.ReadNextAsync();
      
    6. Escriba los valores de las propiedades StatusCode y RequestCharge de la variable response en la consola. Escriba también el valor de la variable id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RUs");
      
  4. Guarde el archivo CosmosHandler.cs.

  5. De nuevo en el terminal, ejecute la aplicación para leer el elemento único mediante una consulta SQL.

    dotnet run -- --name 'Mica Pereira'
    
  6. La salida del comando debe indicar que la consulta requería varias RU.

    [OK]    mica-pereira    2.82 RUs
    
  7. De nuevo en el archivo CosmosHandler.cs, vuelva a eliminar todas las líneas de código del método ManageCustomerAsync, salvo por las dos primeras líneas.

    public static async Task ManageCustomerAsync(string name, string email, string state, string country)
    {
        Container container = await GetContainerAsync();
    
        string id = name.Kebaberize();
    }
    
  8. Para los pasos siguientes, agregue este código dentro del método ManageCustomerAsync.

    1. Cree una nueva instancia de PartitionKeyBuilder agregando los parámetros state y country como un valor de clave de partición de varias partes.

      var partitionKey = new PartitionKeyBuilder()
          .Add(country)
          .Add(state)
          .Build();
      
    2. Use el método ReadItemAsync<> del contenedor para leer el elemento del contenedor mediante las variables id y partitionKey. Guarde el resultado en una variable denominada response.

      var response = await container.ReadItemAsync<dynamic>(
          id: id, 
          partitionKey: partitionKey
      );
      
    3. Escriba los valores de las propiedades StatusCode y RequestCharge de la variable response en la consola. Escriba también el valor de la variable id.

      Console.WriteLine($"[{response.StatusCode}]\t{id}\t{response.RequestCharge} RU");
      
  9. Vuelva a guardar el archivo CosmosHandler.cs.

  10. De nuevo en el terminal, ejecute la aplicación una vez más para que lea el elemento único.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  11. La salida del comando debería indicar que la consulta requería una única RU.

    [OK]    mica-pereira    1 RUs
    

Creación de una transacción con el SDK

Por último, seleccionará el elemento que creó, lo leerá y creará un elemento relacionado diferente como parte de una sola transacción con Microsoft Azure SDK para .NET.

  1. Vuelva al archivo CosmosHandler.cs o ábralo.

  2. Elimine estas líneas de código del 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 los pasos siguientes, agregue este nuevo código dentro del método ManageCustomerAsync.

    1. Cree un nuevo elemento con tipo anónimo mediante los parámetros de método name, statey country, junto con la variable id. Almacene el elemento como una variable denominada customerCart. Este artículo representará un carro de la compra en tiempo real para el cliente que está vacío actualmente.

      var customerCart = new {
          id = $"{Guid.NewGuid()}",
          customerId = id,
          items = new string[] {},
          address = new {
              state = state,
              country = country
          }
      };
      
    2. Cree otro nuevo elemento de tipo anónimo mediante los parámetros de método name, statey country, y la variable id. Almacene el elemento como una variable denominada customerCart. Este elemento representará la información de envío y contacto del cliente.

      var customerContactInfo = new {
          id = $"{id}-contact",
          customerId = id,
          email = email,
          location = $"{state}, {country}",
          address = new {
              state = state,
              country = country
          }
      };
      
    3. Cree un nuevo lote mediante el método CreateTransactionalBatch del contenedor pasando la variable partitionKey. Almacene el lote como una variable denominada batch. Use métodos fluidos para realizar las siguientes acciones:

      Método Parámetro
      ReadItem variable de cadena id
      CreateItem variable de tipo anónimo customerCart
      CreateItem variable de tipo anónimo customerContactInfo
      var batch = container.CreateTransactionalBatch(partitionKey)
          .ReadItem(id)
          .CreateItem(customerCart)
          .CreateItem(customerContactInfo);
      
    4. Use el método ExecuteAsync del lote para iniciar la transacción. Guarde el resultado en una variable denominada response.

      using var response = await batch.ExecuteAsync();
      
    5. Escriba los valores de las propiedades StatusCode y RequestCharge de la variable response en la consola. Escriba también el valor de la variable id.

      Console.WriteLine($"[{response.StatusCode}]\t{response.RequestCharge} RUs");
      
  4. Vuelva a guardar el archivo CosmosHandler.cs.

  5. De nuevo en el terminal, ejecute la aplicación una vez más para que lea el elemento único.

    dotnet run -- --name 'Mica Pereira' --state 'Washington' --country 'United States'
    
  6. La salida del comando debe mostrar las unidades de solicitud usadas para toda la transacción.

    [OK]    16.05 RUs
    

    Nota

    El cargo asociado a la solicitud puede variar.

Validación de los datos finales en Data Explorer

Para resumir, usará Data Explorer en Azure Portal para ver los datos y el contenedor que creó en este tutorial.

  1. Vaya a la cuenta de API for NoSQL en Azure Portal.

  2. En el menú de recursos, seleccione Explorador de datos.

    Screenshot of the Data Explorer option highlighted in the resource menu.

  3. En la página de Data Explorer, expanda la base de datos cosmicworks y seleccione el contenedor customers.

    Screenshot of the selected container node within the database node.

  4. En la barra de comandos, seleccione Nueva consulta SQL.

    Screenshot of the New SQL Query option in the Data Explorer command bar.

  5. En el editor de consultas, fíjese en esta cadena de consulta SQL.

    SELECT * FROM c
    
  6. Seleccione Ejecutar consulta para efectuar la consulta y ver los resultados.

    Screenshot of the Execute Query option in the Data Explorer command bar.

  7. Los resultados deben incluir una matriz JSON con tres elementos creados en este tutorial. Observe que todos los elementos tienen el mismo valor de clave de partición jerárquica, pero campos de identificador únicos. La salida de ejemplo incluida se ha acortado para mayor brevedad.

    [
      {
        "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"
        },
        ...
      }
    ]
    

Limpieza de recursos

Elimine los recursos que utilizados en este artículo cuando ya no se necesiten. Para ello, vaya a la página de la cuenta, seleccione Data Explorer, la cosmicworks base de datos y Eliminar.

Pasos siguientes

Ahora que ha creado su primera aplicación de consola de .NET mediante Azure Cosmos DB, pruebe el siguiente tutorial en el que actualizará una aplicación web existente para usar datos de Azure Cosmos DB.