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

SE APLICA A: NoSQL

El SDK de Azure para .NET permite consultar datos en un contenedor de API for NoSQL mediante LINQ en C# o una cadena de consulta SQL. Este tutorial le guiará por el proceso de actualización de una aplicación web de ASP.NET existente que usa datos de marcador de posición para realizar consultas desde la API.

En este tutorial, aprenderá a:

  • Creación y relleno de una base de datos y un contenedor mediante la API para NoSQL
  • Creación de una aplicación web ASP.NET a partir de una plantilla
  • Consulta de datos desde el contenedor de API for NoSQL mediante el SDK de Azure para .NET

Requisitos previos

Creación de recursos de API for NoSQL

En primer lugar, creará una base de datos y un contenedor en la cuenta de la API for NoSQL existente. A continuación, rellenará esta cuenta con datos mediante la herramienta cosmicworks dotnet.

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

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

    Captura de pantalla de la página de la cuenta de API for NoSQL. La opción Claves está resaltada en el menú de recursos.

  3. En la página Claves, observe y registre el valor del campo CADENA DE CONEXIÓN PRINCIPAL*. Este valor se usará en todo el tutorial.

    Captura de pantalla de la página Claves con los campos URI, Clave principal y Cadena de conexión principal resaltados.

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

    Captura de pantalla de la opción Data Explorer resaltada en el menú de recursos.

  5. En la página Data Explorer, seleccione la opción Nuevo contenedor en la barra de comandos.

    Captura de pantalla de la opción Nuevo contenedor en la barra de comandos Data Explorer.

  6. En el cuadro de diálogo Nuevo contenedor, cree un contenedor con la siguiente configuración:

    Configuración Valor
    Id. de base de datos cosmicworks
    Tipo de rendimiento de la base de datos Manual
    Cantidad de rendimiento de la base de datos 1000
    Id. de contenedor products
    Clave de partición /category/name

    Captura de pantalla del cuadro de diálogo Nuevo contenedor en el Data Explorer con varios valores en cada campo.

    Importante

    En este tutorial, primero se escalará la base de datos hasta 1000 RU/s en rendimiento compartido para maximizar el rendimiento de la migración de datos. Una vez completada la migración de datos, se reducirá verticalmente a 400 RU/s del rendimiento aprovisionado.

  7. Seleccione Aceptar para crear la base de datos y el contenedor.

  8. Abra un terminal para ejecutar comandos para rellenar el contenedor con datos.

    Sugerencia

    También puede usar aquí Azure Cloud Shell.

  9. Instale v2 de la cosmicworks herramienta dotnet desde NuGet.

    dotnet tool install --global cosmicworks  --version 2.*
    
  10. Use la herramienta cosmicworks para rellenar la cuenta de la API for NoSQL con datos de producto de ejemplo mediante los valores URI y PRIMARY KEY que registró anteriormente en este laboratorio. Esos valores registrados se usarán para los parámetros endpoint y key, respectivamente.

    cosmicworks \
        --number-of-products 1759 \
        --number-of-employees 0 \
        --disable-hierarchical-partition-keys \
        --connection-string <nosql-connection-string>
    
  11. Observe la salida de la herramienta de línea de comandos. Debe agregar 1759 elementos al contenedor. La salida de ejemplo incluida se ha acortado para mayor brevedad.

    ── 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. Vuelva a la página Data Explorer de la cuenta.

  13. En la sección Datos, expanda el nodo de base de datos cosmicworks y, a continuación, seleccione Escalar.

    Captura de pantalla de la opción Escalar dentro del nodo de base de datos.

  14. Reduzca el rendimiento de 1000 hasta 400.

    Captura de pantalla de la configuración de rendimiento de la base de datos reducida a 400 RU/s.

  15. En la barra de comandos, seleccione Guardar.

    Captura de pantalla de la opción Guardar en la barra de comandos de Data Explorer.

  16. En la sección Datos, expanda y seleccione el nodo contenedor de productos.

    Captura de pantalla del nodo de contenedor expandido dentro del nodo de base de datos.

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

    Captura de pantalla de la opción Nueva consulta SQL en la barra de comandos de Data Explorer.

  18. En el editor de consultas, agregue esta cadena de consulta SQL.

    SELECT
      p.sku,
      p.price
    FROM products p
    WHERE p.price < 2000
    ORDER BY p.price DESC
    
  19. Seleccione Ejecutar consulta para efectuar la consulta y ver los resultados.

    Captura de pantalla de la opción Ejecutar consulta en la barra de comandos de Data Explorer.

  20. Los resultados deben ser una matriz paginada de todos los elementos del contenedor con un valor price inferior a 2000 ordenados del precio más alto al más bajo. Para mayor brevedad, aquí se incluye un subconjunto de la salida.

    [
      {
        "sku": "BK-R79Y-48",
        "price": 1700.99
      },
      ...
      {
        "sku": "FR-M94B-46",
        "price": 1349.6
      },
    ...
    
  21. Reemplace el contenido del editor de consultas por esta consulta y seleccione Ejecutar consulta de nuevo para observar los resultados.

    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. Los resultados deben ser una matriz más pequeña de elementos filtrados para contener solo elementos que incluyan al menos una etiqueta con un valor de nombre de Tag-32. De nuevo, aquí se incluye un subconjunto de la salida para mayor brevedad.

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

Creación de una aplicación web ASP.NET

Ahora, creará una nueva aplicación web ASP.NET mediante una plantilla de proyecto de ejemplo. A continuación, explorará el código fuente y ejecutará el ejemplo para familiarizarse con la aplicación antes de agregar conectividad de Azure Cosmos DB mediante el SDK de Azure para .NET.

Importante

En este tutorial se extraen paquetes de NuGet de forma transparente. Puede usar dotnet nuget list source para comprobar los orígenes del paquete. Si no tiene NuGet como origen del paquete, use dotnet nuget add source para instalar el sitio como origen.

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

  2. Instale el paquete de plantilla de proyecto cosmicworks.template.web desde NuGet.

    dotnet new install cosmicworks.template.web
    
  3. Cree un nuevo proyecto de aplicación web con la plantilla dotnet new cosmosdbnosql-webapp recién instalada.

    dotnet new cosmosdbnosql-webapp
    
  4. Compile y ejecute el proyecto de aplicación web.

    dotnet run
    
  5. Observe la salida del comando run. La salida debe incluir una lista de puertos y direcciones URL donde se ejecuta la aplicación.

    ...
    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. Abra un nuevo explorador y vaya a la aplicación web en ejecución. Observe las tres páginas de la aplicación en ejecución.

    Captura de pantalla de la aplicación web de ejemplo que se ejecuta con datos de marcador de posición.

  7. Detenga la aplicación en ejecución finalizando el proceso en ejecución.

    Sugerencia

    Use el comando Ctrl+C para detener un proceso en ejecución. Como alternativa, puede cerrar y volver a abrir el terminal.

  8. 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.

  9. Desplácese al archivo Services/ICosmosService.cs y ábralo. Observe las implementaciones de método predeterminadas RetrieveActiveProductsAsync y RetrieveAllProductsAsync. Estos métodos crean una lista estática de productos que se usarán al ejecutar el proyecto por primera vez. Aquí se proporciona un ejemplo truncado de uno de los métodos.

    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. Desplácese al archivo Services/CosmosService.cs y ábralo. Observe la implementación actual de la clase CosmosService. Esta clase implementa la interfaz ICosmosService, pero no invalida ningún método. En este contexto, la clase usará la implementación de interfaz predeterminada hasta que se proporcione una invalidación de la implementación en la interfaz.

    public class CosmosService : ICosmosService
    { }
    
  11. Por último, vaya a y abra los archivos Models/Product.cs y Models/Category.cs. Observe los tipos de registro definidos en cada archivo. Estos tipos se usarán en las consultas de este tutorial.

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

Consulta de datos mediante el SDK de .NET

A continuación, agregará el SDK de Azure para .NET a este proyecto de ejemplo y usará la biblioteca para consultar datos desde el contenedor de la API for NoSQL.

  1. De nuevo en el terminal, agregue el paquete Microsoft.Azure.Cosmos desde NuGet.

    dotnet add package Microsoft.Azure.Cosmos
    
  2. Compile el proyecto.

    dotnet build
    
  3. De nuevo en Visual Studio Code, vuelva a ir al archivo Services/CosmosService.cs.

  4. Agregue una directiva using para el espacio de nombres Microsoft.Azure.Cosmos y Microsoft.Azure.Cosmos.Linq.

    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    
  5. En la clase CosmosService, agregue un nuevo miembro private readonly de tipo CosmosClient denominado _client.

    private readonly CosmosClient _client;
    
  6. Cree un nuevo constructor vacío para la clase CosmosService.

    public CosmosService()
    { }
    
  7. En el constructor, cree una nueva instancia de la clase CosmosClient pasando un parámetro de cadena con el valor PRIMARY CONNECTION STRING que registró anteriormente en el laboratorio. Almacene esta nueva instancia en el miembro _client.

    public CosmosService()
    { 
        _client = new CosmosClient(
            connectionString: "<primary-connection-string>"
        );
    }
    
  8. De nuevo en la clase CosmosService, cree una nueva propiedad private de tipo Container denominada container. Establezca el descriptor de acceso get para devolver la base de datos y cosmicworks el contenedor products.

    private Container container
    {
        get => _client.GetDatabase("cosmicworks").GetContainer("products");
    }
    
  9. Cree un nuevo método asincrónico denominado RetrieveAllProductsAsync que devuelva un valor IEnumerable<Product>.

    public async Task<IEnumerable<Product>> RetrieveAllProductsAsync()
    { }
    
  10. Para los pasos siguientes, agregue este código dentro del método RetrieveAllProductsAsync.

    1. Use el método genérico GetItemLinqQueryable<> para obtener un objeto de tipo IQueryable<> que puede usar para construir una consulta integrada en lenguaje (LINQ). Almacene ese objeto como una variable denominada queryable.

      var queryable = container.GetItemLinqQueryable<Product>();
      
    2. Construya una consulta LINQ mediante los métodos de extensión Where y OrderByDescending. Use el método de extensión ToFeedIterator para crear un iterador para obtener datos de Azure Cosmos DB y almacenar el iterador en una variable denominada feed. Encapsule esta expresión completa en una instrucción using para desechar el iterador más adelante.

      using FeedIterator<Product> feed = queryable
          .Where(p => p.price < 2000m)
          .OrderByDescending(p => p.price)
          .ToFeedIterator();
      
    3. Cree una variable denominada results con el tipo genérico List<>.

      List<Product> results = new();
      
    4. Cree un bucle while que itere hasta que la propiedad HasMoreResults del iterador defeed fuente sea false. Este bucle garantizará que recorra en bucle todas las páginas de resultados del lado servidor.

      while (feed.HasMoreResults)
      { }
      
    5. Dentro del bucle while, llame de forma asincrónica al método ReadNextAsync de la variable feed y almacene el resultado en una variable denominada response.

      while (feed.HasMoreResults)
      {
          var response = await feed.ReadNextAsync();
      }
      
    6. Aún dentro del bucle while, use un bucle foreach para recorrer cada elemento de la respuesta y agregarlos a la lista results.

      while (feed.HasMoreResults)
      {
          var response = await feed.ReadNextAsync();
          foreach (Product item in response)
          {
              results.Add(item);
          }
      }
      
    7. Devuelve la lista results como salida del método RetrieveAllProductsAsync.

      return results;
      
  11. Cree un nuevo método asincrónico denominado RetrieveActiveProductsAsync que devuelva IEnumerable<Product>.

    public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync()
    { }
    
  12. Para los pasos siguientes, agregue este código dentro del método RetrieveActiveProductsAsync.

    1. Cree una nueva cadena denominada sql con una consulta SQL para recuperar varios campos en los que se aplica un filtro (@tagFilter) a la matriz de etiquetas de cada elemento.

      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. 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 red al parámetro @tagFilter.

      var query = new QueryDefinition(
          query: sql
      )
          .WithParameter("@tagFilter", "red");
      
    3. 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 FeedIterator<Product> feed = container.GetItemQueryIterator<Product>(
          queryDefinition: query
      );
      
    4. Use un bucle while para recorrer en iteración varias páginas de resultados y almacenar el valor en un valor List<>denominado results. Devuelve los resultados como salida del método 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. Guarde el archivo Services/CosmosClient.cs.

    Sugerencia

    Si no está seguro de que el código es correcto, puede comprobar el código fuente con el código de ejemplo en GitHub.

Validación de la aplicación final

Por último, ejecutará la aplicación con recargas activas habilitadas. La ejecución de la aplicación validará que el código puede acceder a los datos de la API for NoSQL.

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

    dotnet run
    
  2. La salida del comando run debe incluir una lista de puertos y direcciones URL donde se ejecuta la aplicación. Abra un nuevo explorador y vaya a la aplicación web en ejecución. Observe las tres páginas de la aplicación en ejecución. Ahora, cada página debe incluir datos activos de Azure Cosmos DB.

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 web .NET mediante Azure Cosmos DB, puede profundizar más en el SDK para importar más datos, realizar consultas complejas y administrar los recursos de Azure Cosmos DB for NoSQL.