Introducción a Azure Queue Storage mediante .NET

Información general

Azure Queue Storage proporciona mensajería en la nube entre componentes de aplicaciones. A la hora de diseñar aplicaciones para realizar su escalado, los componentes de las mismas suelen desacoplarse, por lo que se pueden escalar de forma independiente. La instancia de Queue Storage ofrece mensajería asincrónica entre los componentes de las aplicaciones, independientemente de si se ejecutan en la nube, en el escritorio, en un servidor local o en un dispositivo móvil. Además, este tipo de almacenamiento admite la administración de tareas asincrónicas y la creación de flujos de trabajo de procesos.

Acerca de este tutorial

Este tutorial muestra cómo escribir código .NET para algunos escenarios comunes con Azure Queue Storage. Entre los escenarios descritos se incluyen los siguientes: creación y eliminación de colas y adición, lectura y eliminación de mensajes de la cola.

Tiempo estimado para completarla: 45 minutos

Prerrequisitos

¿Qué es Queue Storage?

El almacenamiento en cola de Azure es un servicio para almacenar grandes cantidades de mensajes a los que puede obtenerse acceso desde cualquier lugar del mundo a través de llamadas autenticadas con HTTP o HTTPS. Un único mensaje en cola puede tener un tamaño de hasta 64 KB y una cola puede contener millones de mensajes, hasta el límite de capacidad total de una cuenta de almacenamiento. Queue Storage se usa normalmente para crear un trabajo pendiente del trabajo que se va a procesar de forma asincrónica.

Conceptos del servicio Queue

Azure Queue service contiene los siguientes componentes:

Componentes de Azure Queue service

  • Cuenta de almacenamiento: Todo el acceso a Azure Storage se realiza a través de una cuenta de almacenamiento. Para más información sobre las cuentas de almacenamiento, consulte Introducción a las cuentas de Storage.

  • Cola: una cola contiene un conjunto de mensajes. Todos los mensajes deben encontrarse en una cola. Tenga en cuenta que el nombre de la cola debe ir en minúsculas. Para más información, consulte Asignar nombres a colas y metadatos.

  • Mensaje: un mensaje, en cualquier formato, de hasta 64 KB. El tiempo máximo que un mensaje puede permanecer en la cola es de 7 días. A partir de la versión del 2017-07-29, inclusive, el tiempo de vida máximo puede ser cualquier número positivo o -1, lo que indica que el mensaje no expira. Si se omite este parámetro, el tiempo de vida predeterminado es siete días.

  • Formato de dirección URL: Las colas son direccionables mediante el formato de dirección URL siguiente: http://<storage account>.queue.core.windows.net/<queue>.

    La siguiente dirección URL dirige a una cola del diagrama:

    http://myaccount.queue.core.windows.net/incoming-orders

Creación de una cuenta de Azure Storage

La forma más fácil de crear la primera cuenta de Azure Storage es a través de Azure Portal. Para obtener más información, consulte Crear una cuenta de almacenamiento.

Puede crear también una cuenta de Azure Storage mediante Azure PowerShell, la CLI de Azure o el proveedor de recursos de Azure Storage para .NET.

Si no quiere crear una cuenta de almacenamiento en Azure en este momento, también puede utilizar el emulador de almacenamiento Azurite para ejecutar y probar el código en un entorno local. Para más información, consulte Uso del emulador de Azurite para desarrollo y pruebas locales de Azure Storage.

Configurado su entorno de desarrollo

A continuación, configure el entorno de desarrollo en Visual Studio para poder probar los ejemplos de código de esta guía.

Creación de un proyecto de aplicación de consola de Windows

En Visual Studio, cree una nueva aplicación de consola de Windows. Los siguientes pasos muestran cómo crear una aplicación de consola en Visual Studio 2019. Los pasos son similares en otras versiones de Visual Studio.

  1. Seleccione Archivo > Nuevo > Proyecto
  2. Seleccione Plataforma > Windows
  3. Seleccione Aplicación de consola (.NET Framework)
  4. Seleccione Siguiente.
  5. Escriba el nombre de la aplicación en el campo Nombre del proyecto.
  6. Seleccione Crear

Todos los ejemplos de código de este tutorial se pueden agregar al método Main() del archivo Program.cs de la aplicación de consola.

Las bibliotecas cliente de Azure Storage se pueden usar en cualquier tipo de aplicación .NET, incluidos cualquier servicio en la nube o aplicación web de Azure y aplicaciones de escritorio o móviles. En esta guía, usamos una aplicación de consola para hacerlo más sencillo.

Uso de NuGet para instalar los paquetes necesarios

Para completar este tutorial, es preciso que haga referencia a los siguientes cuatro paquetes en el proyecto:

Puede usar NuGet para obtener estos paquetes. Siga estos pasos:

  1. Haga clic con el botón derecho en el proyecto, en el Explorador de soluciones, y elija Administrar paquetes NuGet.
  2. Seleccione Examinar
  3. Busque Azure.Storage.Queues en línea y seleccione Instalar para instalar la biblioteca cliente de Azure Storage y sus dependencias. También se instalarán las bibliotecas Azure.Storage.Common y Azure.Core, que son dependencias de la biblioteca de colas.
  4. Busque System.Configuration.ConfigurationManager en línea y seleccione Instalar para instalar Configuration Manager.

Determine su entorno de destino

Tiene dos opciones de entorno para ejecutar los ejemplos de esta guía:

  • Puede ejecutar el código en una cuenta de Azure Storage en la nube.
  • Puede ejecutar el código en el emulador de almacenamiento de Azurite. Azurite es un entorno local que emula una cuenta de Azure Storage en la nube. Azurite es una opción gratis para probar y depurar el código mientras la aplicación está en desarrollo. El emulador usa una cuenta y una clave conocidas. Para obtener más información, consulte Uso del emulador Azurite en la instancia local de Azure Storage para desarrollo y pruebas.

Nota

Puede dirigirse al emulador de almacenamiento para evitar incurrir en cualquier coste asociado con Azure Storage. Sin embargo, si selecciona dirigirse a una cuenta de Azure Storage en la nube, los costos derivados de la realización de este tutorial serán insignificantes.

Obtención de la cadena de conexión de almacenamiento

Las bibliotecas cliente de Azure Storage para .NET admiten el uso de una cadena de conexión de almacenamiento para configurar puntos de conexión y credenciales a fin de acceder a los servicios de almacenamiento. Para más información, consulte Administración de las claves de acceso de la cuenta de almacenamiento.

Copia de las credenciales desde Azure Portal

El código de ejemplo debe autorizar el acceso a su cuenta de almacenamiento. Para realizar la autorización, proporcionará a la aplicación sus credenciales de cuenta de almacenamiento en forma de cadena de conexión. Para ver las credenciales de la cuenta de almacenamiento:

  1. Acceda a Azure Portal.

  2. Busque su cuenta de almacenamiento.

  3. En la sección Configuración de la información general de la cuenta de almacenamiento, seleccione Claves de acceso. Aparecen las claves de acceso de la cuenta, así como la cadena de conexión completa de cada clave.

  4. Busque el valor de Cadena de conexión en key1 y haga clic en el botón Copiar para copiar la cadena de conexión. En el paso siguiente, agregará el valor de la cadena de conexión a una variable de entorno.

    Captura de pantalla que muestra cómo copiar una cadena de conexión desde Azure Portal

Para más información acerca de las cadenas de conexión, consulte Configuración de una cadena de conexión a Azure Storage.

Nota

La clave de la cuenta de almacenamiento es similar a la contraseña raíz de la cuenta de almacenamiento. Siempre debe proteger la clave de la cuenta de almacenamiento. Evite distribuirla a otros usuarios, codificarla de forma rígida o guardarla en un archivo de texto que sea accesible a otros usuarios. Vuelva a generar la clave mediante Azure Portal si cree que puede verse comprometida.

La mejor manera de conservar la cadena de conexión de almacenamiento es mediante un archivo de configuración. Para configurar la cadena de conexión, abra el archivo app.config en el Explorador de soluciones de Visual Studio. Agregue el contenido del elemento <appSettings>, que se muestra aquí. Reemplace la connection-string con el valor que copió de la cuenta de almacenamiento en el portal:

<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
    <appSettings>
        <add key="StorageConnectionString" value="connection-string" />
    </appSettings>
</configuration>

Por ejemplo, el valor de configuración es similar a:

<add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=storagesample;AccountKey=GMuzNHjlB3S9itqZJHHCnRkrokLkcSyW7yK9BRbGp0ENePunLPwBgpxV1Z/pVo9zpem/2xSHXkMqTHHLcx8XRA==EndpointSuffix=core.windows.net" />

Para elegir como destino el emulador de almacenamiento Azurite, puede utilizar un acceso directo que se asigna al nombre y la clave conocidas de la cuenta. En ese caso, la configuración de la cadena de conexión es:

<add key="StorageConnectionString" value="UseDevelopmentStorage=true" />

Adición de directivas using

Agregue las siguientes directivas using al principio del archivo Program.cs:

using System; // Namespace for Console output
using System.Configuration; // Namespace for ConfigurationManager
using System.Threading.Tasks; // Namespace for Task
using Azure.Identity;
using Azure.Storage.Queues; // Namespace for Queue storage types
using Azure.Storage.Queues.Models; // Namespace for PeekedMessage

Creación del cliente de Queue Storage

La clase QueueClient permite recuperar las colas almacenadas en Queue Storage. Esta es una forma de crear el cliente de servicio:

//-------------------------------------------------
// Create the queue service client
//-------------------------------------------------
public void CreateQueueClient(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to create and manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);
}

Ahora ya puede escribir código que lee y escribe datos en Queue Storage.

Creación de una cola

En este ejemplo se muestra cómo crear una cola:

//-------------------------------------------------
// Create a message queue
//-------------------------------------------------
public bool CreateQueue(string queueName)
{
    try
    {
        // Get the connection string from app settings
        string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

        // Instantiate a QueueClient which will be used to create and manipulate the queue
        QueueClient queueClient = new QueueClient(connectionString, queueName);

        // Create the queue
        queueClient.CreateIfNotExists();

        if (queueClient.Exists())
        {
            Console.WriteLine($"Queue created: '{queueClient.Name}'");
            return true;
        }
        else
        {
            Console.WriteLine($"Make sure the Azurite storage emulator running and try again.");
            return false;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}\n\n");
        Console.WriteLine($"Make sure the Azurite storage emulator running and try again.");
        return false;
    }
}

un mensaje en una cola

Para insertar un mensaje en una cola existente, llame al método SendMessage. Un mensaje puede ser una cadena (en formato UTF-8) o una matriz de bytes. En el código siguiente se crea una cola (si es que no existe) y se inserta un mensaje:

//-------------------------------------------------
// Insert a message into a queue
//-------------------------------------------------
public void InsertMessage(string queueName, string message)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to create and manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    // Create the queue if it doesn't already exist
    queueClient.CreateIfNotExists();

    if (queueClient.Exists())
    {
        // Send a message to the queue
        queueClient.SendMessage(message);
    }

    Console.WriteLine($"Inserted: {message}");
}

siguiente mensaje

Puede inspeccionar el mensaje de la cola sin tener que quitarlo de ella, mediante una llamada al método PeekMessages. Si no pasa un valor para el parámetro maxMessages, el valor predeterminado es inspeccionar un mensaje.

//-------------------------------------------------
// Peek at a message in the queue
//-------------------------------------------------
public void PeekMessage(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    { 
        // Peek at the next message
        PeekedMessage[] peekedMessage = queueClient.PeekMessages();

        // Display the message
        Console.WriteLine($"Peeked message: '{peekedMessage[0].Body}'");
    }
}

contenido de un mensaje en cola

Puede cambiar el contenido de un mensaje local en la cola. Si el mensaje representa una tarea de trabajo, puede usar esta característica para actualizar el estado de la tarea de trabajo. El siguiente código actualiza el mensaje de la cola con contenido nuevo y amplía el tiempo de espera de la visibilidad en 60 segundos más. De este modo, se guarda el estado de trabajo asociado al mensaje y se le proporciona al cliente un minuto más para que siga elaborando el mensaje. Esta técnica se puede utilizar para realizar un seguimiento de los flujos de trabajo de varios pasos en los mensajes en cola, sin que sea necesario volver a empezar desde el principio si se produce un error en un paso del proceso a causa de un error de hardware o software. Normalmente, también mantendría un número de reintentos y, si el mensaje se intentara más de n veces, lo eliminaría. Esto proporciona protección frente a un mensaje que produce un error en la aplicación cada vez que se procesa.

//-------------------------------------------------
// Update an existing message in the queue
//-------------------------------------------------
public void UpdateMessage(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        // Get the message from the queue
        QueueMessage[] message = queueClient.ReceiveMessages();

        // Update the message contents
        queueClient.UpdateMessage(message[0].MessageId, 
                message[0].PopReceipt, 
                "Updated contents",
                TimeSpan.FromSeconds(60.0)  // Make it invisible for another 60 seconds
            );
    }
}

Extracción del siguiente mensaje de la cola

Quitar un mensaje de una cola en dos pasos. Si llama a ReceiveMessages, obtiene el siguiente mensaje en una cola. Un mensaje devuelto por ReceiveMessages se hace invisible a cualquier otro código de lectura de mensajes de esta cola. De forma predeterminada, este mensaje permanece invisible durante 30 segundos. Para acabar de quitar el mensaje de la cola, también debe llamar a DeleteMessage. Este proceso de extracción de un mensaje que consta de dos pasos garantiza que si su código no puede procesar un mensaje a causa de un error de hardware o software, otra instancia de su código puede obtener el mismo mensaje e intentarlo de nuevo. El código siguiente llama a DeleteMessage justo después de haberse procesado el mensaje.

//-------------------------------------------------
// Process and remove a message from the queue
//-------------------------------------------------
public void DequeueMessage(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        // Get the next message
        QueueMessage[] retrievedMessage = queueClient.ReceiveMessages();

        // Process (i.e. print) the message in less than 30 seconds
        Console.WriteLine($"Dequeued message: '{retrievedMessage[0].Body}'");

        // Delete the message
        queueClient.DeleteMessage(retrievedMessage[0].MessageId, retrievedMessage[0].PopReceipt);
    }
}

Uso del patrón Async-Await con API comunes de Queue Storage

En este ejemplo se muestra cómo usar el patrón Async-Await con API comunes de Queue Storage. El ejemplo llama a la versión asincrónica de cada uno de los métodos indicados, tal como se puede ver por el sufijo Async de cada método. Cuando se utiliza un método asincrónico, el patrón Async-Await suspende la ejecución local hasta que se completa la llamada. Este comportamiento permite que el subproceso actual realice otro trabajo, lo que ayuda a evitar cuellos de botella en el rendimiento y mejora la capacidad de respuesta general de la aplicación. Para más información sobre el uso del patrón Async-Await en. NET, consulte Async y Await (C# y Visual Basic)

//-------------------------------------------------
// Perform queue operations asynchronously
//-------------------------------------------------
public async Task QueueAsync(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    // Create the queue if it doesn't already exist
    await queueClient.CreateIfNotExistsAsync();

    if (await queueClient.ExistsAsync())
    {
        Console.WriteLine($"Queue '{queueClient.Name}' created");
    }
    else
    {
        Console.WriteLine($"Queue '{queueClient.Name}' exists");
    }

    // Async enqueue the message
    await queueClient.SendMessageAsync("Hello, World");
    Console.WriteLine($"Message added");

    // Async receive the message
    QueueMessage[] retrievedMessage = await queueClient.ReceiveMessagesAsync();
    Console.WriteLine($"Retrieved message with content '{retrievedMessage[0].Body}'");

    // Async delete the message
    await queueClient.DeleteMessageAsync(retrievedMessage[0].MessageId, retrievedMessage[0].PopReceipt);
    Console.WriteLine($"Deleted message: '{retrievedMessage[0].Body}'");

    // Async delete the queue
    await queueClient.DeleteAsync();
    Console.WriteLine($"Deleted queue: '{queueClient.Name}'");
}

Uso de opciones adicionales para quitar mensajes de la cola

Hay dos formas de personalizar la recuperación de mensajes de una cola. En primer lugar, puede obtener un lote de mensajes (hasta 32). En segundo lugar, puede establecer un tiempo de espera de la invisibilidad más largo o más corto para que el código disponga de más o menos tiempo para procesar cada mensaje.

El siguiente ejemplo de código usa el método ReceiveMessages para obtener 20 mensajes en una llamada. A continuación, procesa cada mensaje con un bucle foreach. También establece el tiempo de espera de la invisibilidad en cinco minutos para cada mensaje. Tenga en cuenta que los 5 minutos empiezan a contar para todos los mensajes al mismo tiempo, por lo que después de pasar los 5 minutos desde la llamada a ReceiveMessages, todos los mensajes que no se han eliminado volverán a estar visibles.

//-----------------------------------------------------
// Process and remove multiple messages from the queue
//-----------------------------------------------------
public void DequeueMessages(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        // Receive and process 20 messages
        QueueMessage[] receivedMessages = queueClient.ReceiveMessages(20, TimeSpan.FromMinutes(5));

        foreach (QueueMessage message in receivedMessages)
        {
            // Process (i.e. print) the messages in less than 5 minutes
            Console.WriteLine($"De-queued message: '{message.Body}'");

            // Delete the message
            queueClient.DeleteMessage(message.MessageId, message.PopReceipt);
        }
    }
}

la longitud de la cola

Puede obtener una estimación del número de mensajes existentes en una cola. El método GetProperties devuelve propiedades de cola, incluido el recuento de mensajes. La propiedad ApproximateMessagesCount obtiene el número aproximado de mensajes en la cola. Este número no es menor que el número real de mensajes de la cola, pero podría ser mayor.

//-----------------------------------------------------
// Get the approximate number of messages in the queue
//-----------------------------------------------------
public void GetQueueLength(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        QueueProperties properties = queueClient.GetProperties();

        // Retrieve the cached approximate message count.
        int cachedMessagesCount = properties.ApproximateMessagesCount;

        // Display number of messages.
        Console.WriteLine($"Number of messages in queue: {cachedMessagesCount}");
    }
}

Eliminación de una cola

Para eliminar una cola y todos los mensajes contenidos en ella, llame al método Delete en el objeto de cola.

//-------------------------------------------------
// Delete the queue
//-------------------------------------------------
public void DeleteQueue(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        // Delete the queue
        queueClient.Delete();
    }

    Console.WriteLine($"Queue deleted: '{queueClient.Name}'");
}

Pasos siguientes

Ahora que está familiarizado con los aspectos básicos de Queue Storage, utilice estos vínculos para obtener más información acerca de tareas de almacenamiento más complejas.