Esercizio - Inviare e ricevere messaggi usando una coda
Si è scelto di usare una coda del bus di servizio per la gestione di messaggi relativi alle singole vendite tra l'app per dispositivi mobili usata dal personale di vendita e il servizio Web, ospitato in Azure, che archivia i dettagli di ogni vendita in un'istanza di database SQL di Azure.
Nell'esercizio precedente sono stati implementati gli oggetti necessari nella sottoscrizione di Azure. Ora si vuole scrivere il codice che invia i messaggi alla coda e recupera i messaggi.
In questa unità verranno compilate due applicazioni console: un'applicazione inserisce i messaggi in una coda del bus di servizio e un'applicazione recupera i messaggi da una coda del bus di servizio. Le applicazioni fanno parte di un'unica soluzione .NET Core.
Ottenere la stringa di connessione allo spazio dei nomi del bus di servizio
È necessario configurare due informazioni nelle due app console per accedere allo spazio dei nomi del bus di servizio e usare la coda all'interno di tale spazio dei nomi:
- Endpoint per lo spazio dei nomi
- Chiave di accesso condiviso per l'autenticazione
È possibile ottenere questi valori dalla stringa di connessione.
Nella finestra di Cloud Shell a destra dello schermo, selezionare l'icona Altro (...), quindi selezionare Impostazioni>Vai alla versione classica.
Eseguire il comando seguente, sostituendo
<namespace-name>
con lo spazio dei nomi del bus di servizio creato nell'ultimo esercizio.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>
L'ultima riga nella risposta è la stringa di connessione, che contiene l'endpoint per lo spazio dei nomi e la chiave di accesso condiviso. Dovrebbe essere simile all'esempio seguente:
Endpoint=sb://example.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxxxx
Copiare la stringa di connessione da Cloud Shell. Questa stringa di connessione dovrà essere usata più volte in questo modulo, pertanto è consigliabile salvarla in una posizione accessibile.
Clonare e aprire l'applicazione iniziale
Nota
Per semplicità, le attività seguenti indicano di impostare la stringa di connessione come hardcoded nel file Program.cs di entrambe le applicazioni console. In un'applicazione di produzione si dovrebbe usare un file di configurazione o Azure Key Vault per archiviare la stringa di connessione.
Eseguire il comando seguente in Cloud Shell per clonare la soluzione del progetto Git:
cd ~ git clone https://github.com/MicrosoftDocs/mslearn-connect-services-together.git
Eseguire il comando seguente per passare alla cartella start nel progetto clonato e aprire l'editor di Cloud Shell:
cd ~/mslearn-connect-services-together/implement-message-workflows-with-service-bus/src/start code .
Scrivere il codice per inviare un messaggio a una coda
Nell'editor di CloudShell aprire privatemessagesender/Program.cs e individuare la riga di codice seguente:
const string ServiceBusConnectionString = "";
Incollare la stringa di connessione tra virgolette.
Se è stato usato un nome diverso da salesmessages per il nome della coda, aggiornare il valore per la proprietà
QueueName
nel codice:const string QueueName = "salesmessages";
Per completare il componente che invia messaggi sulle vendite, è necessario aggiungere un operatore
await
per sospendere la valutazione del metodo asincrono fino al completamento dell'operazione asincrona. Trovare il metodoSendSalesMessageAsync()
. All'interno di questo metodo individuare la riga di codice seguente:// Create a Service Bus client here
Sostituire la riga di codice con il codice seguente:
// 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);
All'interno del metodo
SendSalesMessageAsync()
individuare la riga di codice seguente:// Create a sender here
Sostituire il commento con il codice seguente:
await using ServiceBusSender sender = client.CreateSender(QueueName);
All'interno del blocco
try...catch
individuare la riga di codice seguente:// Create and send a message here
Sostituire la riga di codice con le righe di codice seguenti:
string messageBody = $"$10,000 order for bicycle parts from retailer Adventure Works."; var message = new ServiceBusMessage(messageBody);
Inserire il codice seguente in una nuova riga direttamente sotto ciò che è stato appena aggiunto per visualizzare il messaggio nella console:
Console.WriteLine($"Sending message: {messageBody}");
Inserire il codice seguente nella riga successiva:
await sender.SendMessageAsync(message);
Per eliminare gli oggetti mittente e client, alla fine del file, individuare il commento seguente:
// Close the connection to the sender here
Sostituire la riga con il codice seguente:
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(); }
Verificare che il codice finale per privatemessagesender/Program.cs sia simile all'esempio seguente:
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(); } } } }
Per salvare le modifiche, premere CTRL+S e quindi CTRL+Q per chiudere l'editor.
Inviare un messaggio alla coda
In Cloud Shell, eseguire il comando seguente per inviare un messaggio relativo a una vendita. La prima riga assicura di trovarsi nel percorso corretto.
cd ~/mslearn-connect-services-together/implement-message-workflows-with-service-bus/src/start dotnet run --project ./privatemessagesender
Nota
La prima volta che si eseguono le app in questo esercizio, consentire a
dotnet
di ripristinare i pacchetti da origini remote e compilare le app.Durante l'esecuzione del programma, i messaggi vengono stampati nella console per indicare che l'app invia un messaggio:
Sending a message to the Sales Messages queue... Sending message: $10,000 order for bicycle parts from retailer Adventure Works. Message was sent successfully.
Al termine dell'app, eseguire il comando seguente, sostituendo <namespace-name> con il nome dello spazio dei nomi del bus di servizio. Questo comando restituisce il numero di messaggi presenti nella coda.
az servicebus queue show \ --resource-group "<rgn>[sandbox resource group name]</rgn>" \ --name salesmessages \ --query messageCount \ --namespace-name <namespace-name>
Eseguire di nuovo il comando
dotnet run
dal passaggio 1, quindi eseguire di nuovo il comandoservicebus queue show
. Ogni volta che si esegue l'app dotnet, viene aggiunto un nuovo messaggio alla coda.messageCount
aumenterà ogni volta che si esegue il comando di Azure.
Scrivere il codice per ricevere messaggi dalla coda
Eseguire il comando seguente per aprire di nuovo l'editor:
code .
Nell'editor aprire privatemessagereceiver/Program.cs e individuare la riga di codice seguente:
const string ServiceBusConnectionString = "";
Incollare la stringa di connessione salvata in precedenza tra virgolette.
Trovare il metodo
ReceiveSalesMessageAsync()
. All'interno di questo metodo individuare la riga di codice seguente:// Create a Service Bus client that will authenticate using a connection string
Sostituire la riga con il codice seguente:
var client = new ServiceBusClient(ServiceBusConnectionString);
Per configurare le opzioni di gestione dei messaggi, individuare la riga di codice seguente:
// Create the options to use for configuring the processor
Sostituire la riga con le righe di codice seguenti:
var processorOptions = new ServiceBusProcessorOptions { MaxConcurrentCalls = 1, AutoCompleteMessages = false };
Per creare un processore, individuare la riga di codice seguente:
// Create a processor that we can use to process the messages
Sostituire la riga con il codice seguente:
await using ServiceBusProcessor processor = client.CreateProcessor(QueueName, processorOptions);
Per configurare i gestori, individuare la riga di codice seguente:
// Configure the message and error handler to use
Sostituire la riga con il codice seguente:
processor.ProcessMessageAsync += MessageHandler; processor.ProcessErrorAsync += ErrorHandler;
Per avviare l'elaborazione, individuare la riga di codice seguente:
// Start processing
Sostituire la riga con il codice seguente:
await processor.StartProcessingAsync();
Per chiudere la connessione al bus di servizio, individuare la riga di codice seguente:
// Close the processor here
Sostituire la riga con il codice seguente:
await processor.CloseAsync();
Esaminare il codice nel metodo
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); }
Esaminare il codice nel metodo
ErrorHandler
:// handle any errors when receiving messages static Task ErrorHandler(ProcessErrorEventArgs args) { // print the exception message Console.WriteLine(args.Exception.ToString()); return Task.CompletedTask; }
Verificare che il codice finale per privatemessagereceiver/Program.cs sia simile all'esempio seguente:
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; } } }
Per salvare le modifiche, premere CTRL+S e quindi CTRL+Q per chiudere l'editor.
Ricevere un messaggio dalla coda
Per eseguire il componente che riceve un messaggio su una vendita, eseguire questo comando in Cloud Shell:
dotnet run --project privatemessagereceiver
Controllare le notifiche in Cloud Shell. Nel portale di Azure passare allo spazio dei nomi del bus di servizio e controllare il grafico Messaggi:
Received: $10,000 order for bicycle parts from retailer Adventure Works.
Quando si nota che i messaggi sono stati ricevuti in Cloud Shell, premere INVIO per arrestare l'app.
Controllare il numero di messaggi
Eseguire il codice seguente per verificare che tutti i messaggi siano stati rimossi dalla coda, ricordando di sostituire <namespace-name> con lo spazio dei nomi del bus di servizio.
az servicebus queue show \
--resource-group "<rgn>[sandbox resource group name]</rgn>" \
--name salesmessages \
--query messageCount \
--namespace-name <namespace-name>
Se tutti i messaggi sono stati rimossi verrà visualizzato 0
.
È stato scritto codice che invia un messaggio sulle singole vendite a una coda del bus di servizio. Nell'applicazione distribuita per la forza vendita è necessario scrivere questo codice nell'app per dispositivi mobili usata dal personale di vendita.
È stato scritto anche il codice che riceve un messaggio dalla coda del bus di servizio. Nell'applicazione distribuita per la forza vendita è necessario scrivere questo codice nel servizio Web in esecuzione in Azure che elabora i messaggi ricevuti.