Ejercicio: Envío y recepción de mensajes mediante una cola

Completado

Ha elegido usar una cola de Service Bus para controlar los mensajes sobre ventas individuales entre la aplicación móvil que usa el personal de ventas y el servicio web hospedado en Azure, que almacena detalles sobre cada venta en una instancia de Azure SQL Database.

En el ejercicio anterior ha implementado los objetos necesarios en la suscripción de Azure. Ahora quiere escribir el código que envía mensajes a esa cola y los recupera.

En esta unidad va a compilar dos aplicaciones de consola: una aplicación coloca mensajes en una cola de Service Bus y otra los recupera de una cola de Service Bus. Las aplicaciones son parte de una única solución de .NET Core.

Obtención de la cadena de conexión del espacio de nombres de Service Bus

Para acceder al espacio de nombres de Service Bus y usar la cola de ese espacio de nombres, debe configurar dos fragmentos de información en las dos aplicaciones de consola:

  • El punto de conexión para el espacio de nombres.
  • La clave de acceso compartido para la autenticación.

Puede obtener estos valores de la cadena de conexión.

  1. En la parte superior derecha de la ventana de Cloud Shell, seleccione el icono Más (...) y después Configuración>Ir a la versión clásica.

  2. Ejecute el siguiente comando, reemplazando <namespace-name> por el espacio de nombres de Service Bus que creó en el último ejercicio.

    az servicebus namespace authorization-rule keys list \
        --resource-group "<rgn>[sandbox resource group name]</rgn>" \
        --name RootManageSharedAccessKey \
        --query primaryConnectionString \
        --output tsv \
        --namespace-name <namespace-name>
    

    La última línea de la respuesta es la cadena de conexión, que contiene el punto de conexión del espacio de nombres y la clave de acceso compartida. Debería ser similar al ejemplo siguiente:

    Endpoint=sb://example.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxxxx
    
  3. Copie la cadena de conexión de Cloud Shell. Va a necesitar esta cadena de conexión varias veces a lo largo de este módulo, por lo que quizás quiera guardarla donde la tenga a mano.

Clonación y apertura de la aplicación de inicio

Nota:

Por simplicidad, en las siguientes tareas se le indica que codifique de forma rígida la cadena de conexión en el archivo Program.cs de ambas aplicaciones de consola. En una aplicación de producción debería usar un archivo de configuración o Azure Key Vault para almacenar la cadena de conexión.

  1. Ejecute el siguiente comando en Cloud Shell para clonar la solución del proyecto de Git:

    cd ~
    git clone https://github.com/MicrosoftDocs/mslearn-connect-services-together.git
    
  2. Ejecute el siguiente comando para ir a la carpeta de inicio del proyecto clonado y abrir el editor de Cloud Shell:

    cd ~/mslearn-connect-services-together/implement-message-workflows-with-service-bus/src/start
    code .
    

Escritura de código para enviar un mensaje a una cola

  1. En el editor de Cloud Shell, abra privatemessagesender/Program.cs y busque la siguiente línea de código:

    const string ServiceBusConnectionString = "";
    

    Pegue la cadena de conexión entre las comillas.

  2. Si ha usado un nombre distinto de salesmessages para el nombre de la cola, actualice el valor de la propiedad QueueName en el código:

    const string QueueName = "salesmessages";
    
  3. Para completar el componente que envía mensajes sobre las ventas, debe agregar un operador await para suspender la evaluación del método asincrónico hasta que se complete la operación asincrónica. Busque el método SendSalesMessageAsync(). Dentro del método, busque la siguiente línea de código:

    // Create a Service Bus client here
    

    Reemplace la línea de código por el código siguiente:

    // By leveraging "await using", the DisposeAsync method will be called automatically once the client variable goes out of scope. 
    // In more realistic scenarios, you would want to store off a class reference to the client (rather than a local variable) so that it can be used throughout your program.
    
    await using var client = new ServiceBusClient(ServiceBusConnectionString);
    
  4. En el método SendSalesMessageAsync(), busque la siguiente línea de código:

    // Create a sender here
    

    Reemplace ese comentario por el código siguiente:

    await using ServiceBusSender sender = client.CreateSender(QueueName);
    
  5. En el bloque try...catch, busque la siguiente línea de código:

    // Create and send a message here
    

    Reemplace la línea de código por las líneas de código siguientes:

    string messageBody = $"$10,000 order for bicycle parts from retailer Adventure Works.";
    var message = new ServiceBusMessage(messageBody);
    
  6. Inserte el código siguiente en una línea nueva directamente debajo de lo que acaba de agregar para mostrar el mensaje en la consola:

    Console.WriteLine($"Sending message: {messageBody}");
    
  7. Inserte el código siguiente en la línea que sigue:

    await sender.SendMessageAsync(message);
    
  8. Para eliminar los objetos de remitente y cliente, cerca del final del archivo, busque el comentario siguiente:

    // Close the connection to the sender here
    

    Reemplace la línea con el código siguiente:

    finally
    {
        // Calling DisposeAsync on client types is required to ensure that network
        // resources and other unmanaged objects are properly cleaned up.
        await sender.DisposeAsync();
        await client.DisposeAsync();
    }
    
  9. Compruebe que el código final de privatemessagesender/Program.cs sea similar al ejemplo siguiente:

    using System;
    using System.Text;
    using System.Threading.Tasks;
    using Azure.Messaging.ServiceBus;
    
    namespace privatemessagesender
    {
        class Program
        {
            const string ServiceBusConnectionString = "Endpoint=sb://example.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxx";
            const string QueueName = "salesmessages";
    
            static void Main(string[] args)
            {
                Console.WriteLine("Sending a message to the Sales Messages queue...");
                SendSalesMessageAsync().GetAwaiter().GetResult();
                Console.WriteLine("Message was sent successfully.");
            }
    
            static async Task SendSalesMessageAsync()
            {
                await using var client = new ServiceBusClient(ServiceBusConnectionString);
    
                await using ServiceBusSender sender = client.CreateSender(QueueName);
                try
                {
                    string messageBody = $"$10,000 order for bicycle parts from retailer Adventure Works.";
                    var message = new ServiceBusMessage(messageBody);
                    Console.WriteLine($"Sending message: {messageBody}");
                    await sender.SendMessageAsync(message);
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"{DateTime.Now} :: Exception: {exception.Message}");
                }
                finally
                {
                    // Calling DisposeAsync on client types is required to ensure that network
                    // resources and other unmanaged objects are properly cleaned up.
                    await sender.DisposeAsync();
                    await client.DisposeAsync();
                }
            }
        }
    }
    
  10. Para guardar los cambios, presione Ctrl+S y, después, Ctrl+Q para cerrar el editor.

Enviar un mensaje a la cola

  1. En Cloud Shell, ejecute el siguiente comando para enviar un mensaje sobre una venta. La primera línea garantiza que se encuentra en la ruta de acceso correcta.

    cd ~/mslearn-connect-services-together/implement-message-workflows-with-service-bus/src/start
    dotnet run --project ./privatemessagesender
    

    Nota:

    La primera vez que ejecute las aplicaciones de este ejercicio, permita a dotnet restaurar paquetes desde orígenes remotos y compilar las aplicaciones.

    A medida que se ejecuta el programa, se imprimen mensajes en la consola que indican que la aplicación está enviando un mensaje:

    Sending a message to the Sales Messages queue...
    Sending message: $10,000 order for bicycle parts from retailer Adventure Works.
    Message was sent successfully.
    
  2. Cuando la aplicación haya terminado, ejecute el comando siguiente, y reemplace <nombre_del_espacio_de_nombres> por el nombre del espacio de nombres de Service Bus. Este comando devuelve el número de mensajes que hay en la cola.

    az servicebus queue show \
        --resource-group "<rgn>[sandbox resource group name]</rgn>" \
        --name salesmessages \
        --query messageCount \
        --namespace-name <namespace-name>
    
  3. Vuelva a ejecutar el comando dotnet run a partir del paso 1 y luego vuelva a ejecutar el comando servicebus queue show. Cada vez que ejecuta la aplicación dotnet, se agrega un nuevo mensaje a la cola. Va a ver que messageCount aumenta cada vez que se ejecuta el comando de Azure.

Escritura de código para recibir mensajes de la cola

  1. Ejecute el siguiente comando para abrir de nuevo el editor:

    code .
    
  2. En el editor, abra privatemessagereceiver/Program.cs y busque la siguiente línea de código:

    const string ServiceBusConnectionString = "";
    

    Pegue entre comillas la cadena de conexión que guardó anteriormente.

  3. Busque el método ReceiveSalesMessageAsync(). Dentro del método, busque la siguiente línea de código:

    // Create a Service Bus client that will authenticate using a connection string
    

    Reemplace la línea con el código siguiente:

    var client = new ServiceBusClient(ServiceBusConnectionString);
    
  4. Para configurar las opciones de control de mensajes, busque la siguiente línea de código:

    // Create the options to use for configuring the processor
    

    Reemplace esa línea por las líneas de código siguientes:

    var processorOptions = new ServiceBusProcessorOptions
    {
        MaxConcurrentCalls = 1,
        AutoCompleteMessages = false
    };
    
  5. Para crear un procesador, busque la siguiente línea de código:

    // Create a processor that we can use to process the messages
    

    Reemplace la línea con el código siguiente:

    await using ServiceBusProcessor processor = client.CreateProcessor(QueueName, processorOptions);
    
  6. Para configurar los controladores, busque la siguiente línea de código:

    // Configure the message and error handler to use
    

    Reemplace la línea con el código siguiente:

    processor.ProcessMessageAsync += MessageHandler;
    processor.ProcessErrorAsync += ErrorHandler;
    
  7. Para empezar a procesar, busque la siguiente línea de código:

    // Start processing
    

    Reemplace la línea con el código siguiente:

    await processor.StartProcessingAsync();
    
  8. Para cerrar la conexión a Service Bus, busque la siguiente línea de código:

    // Close the processor here
    

    Reemplace la línea con el código siguiente:

    await processor.CloseAsync();
    
  9. Revise el código en el método MessageHandler:

    // handle received messages
    static async Task MessageHandler(ProcessMessageEventArgs args)
    {
        // extract the message
        string body = args.Message.Body.ToString();
    
        // print the message
        Console.WriteLine($"Received: {body}");
    
        // complete the message so that message is deleted from the queue. 
        await args.CompleteMessageAsync(args.Message);
    }
    
  10. Revise el código en el método ErrorHandler:

    // handle any errors when receiving messages
    static Task ErrorHandler(ProcessErrorEventArgs args)
    {
        // print the exception message
        Console.WriteLine(args.Exception.ToString());
        return Task.CompletedTask;
    }    
    
  11. Compruebe que el código final de privatemessagereceiver/Program.cs sea similar al ejemplo siguiente:

    using System;
    using System.Text;
    using System.Threading.Tasks;
    using Azure.Messaging.ServiceBus;
    
    namespace privatemessagereceiver
    {
        class Program
        {
    
            const string ServiceBusConnectionString = "Endpoint=sb://<examplenamespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
            const string QueueName = "salesmessages";
    
            static void Main(string[] args)
            {
    
                ReceiveSalesMessageAsync().GetAwaiter().GetResult();
    
            }
    
            static async Task ReceiveSalesMessageAsync()
            {
    
                Console.WriteLine("======================================================");
                Console.WriteLine("Press ENTER key to exit after receiving all the messages.");
                Console.WriteLine("======================================================");
    
    
                var client = new ServiceBusClient(ServiceBusConnectionString);
    
                var processorOptions = new ServiceBusProcessorOptions
                {
                    MaxConcurrentCalls = 1,
                    AutoCompleteMessages = false
                };
    
                await using ServiceBusProcessor processor = client.CreateProcessor(QueueName, processorOptions);
    
                processor.ProcessMessageAsync += MessageHandler;
                processor.ProcessErrorAsync += ErrorHandler;
    
    
                await processor.StartProcessingAsync();
    
                Console.Read();
    
                await processor.CloseAsync();
    
            }
    
            // handle received messages
            static async Task MessageHandler(ProcessMessageEventArgs args)
            {
                string body = args.Message.Body.ToString();
                Console.WriteLine($"Received: {body}");
    
                // complete the message. messages is deleted from the queue. 
                await args.CompleteMessageAsync(args.Message);
            }
    
            // handle any errors when receiving messages
            static Task ErrorHandler(ProcessErrorEventArgs args)
            {
                Console.WriteLine(args.Exception.ToString());
                return Task.CompletedTask;
            }
        }
    }
    
    
  12. Para guardar los cambios, presione Ctrl+S y, después, Ctrl+Q para cerrar el editor.

Recepción de un mensaje desde la cola

  1. Para ejecutar el componente que recibe un mensaje sobre una venta, ejecute este comando en Cloud Shell:

    dotnet run --project privatemessagereceiver
    
  2. Compruebe las notificaciones en Cloud Shell. En Azure Portal, vaya al espacio de nombres de Service Bus y compruebe el gráfico Mensajes:

    Received: $10,000 order for bicycle parts from retailer Adventure Works.
    
  3. Cuando vea que los mensajes se han recibido en Cloud Shell, presione ENTRAR para detener la aplicación.

Comprobación del número de mensajes

Ejecute el código siguiente para confirmar que todos los mensajes se han quitado de la cola, y acuérdese de reemplazar <nombre_del_espacio_de_nombres> por el espacio de nombres de Service Bus.

az servicebus queue show \
    --resource-group "<rgn>[sandbox resource group name]</rgn>" \
    --name salesmessages \
    --query messageCount \
    --namespace-name <namespace-name>

La salida mostrará 0 si se han quitado todos los mensajes.

Ha escrito código que envía un mensaje sobre las ventas individuales a una cola de Service Bus. En la aplicación distribuida de Salesforce, debería escribir este código en la aplicación móvil que el personal de ventas usa en los dispositivos.

También ha escrito código que recibe un mensaje de la cola de Service Bus. En la aplicación distribuida de Salesforce, debe escribir este código en el servicio web que se ejecuta en Azure y procesa los mensajes recibidos.