練習 - 使用主題來傳送及接收訊息

已完成

您已決定使用 Azure 服務匯流排主題,在您的銷售人力應用程式中發佈銷售績效訊息。 銷售人員會在自己的行動裝置上使用此應用程式,傳送每個區域和時段的銷售數字摘要訊息。 這些訊息會散發到位於公司營運區域 (包括美洲和歐洲) 的網路服務。

您已在此主題的 Azure 訂用帳戶中實作了必要的基礎結構。 您現在想要撰寫程式碼以將訊息傳送至主題,並撰寫程式碼從訂用帳戶擷取訊息。 然後,您會將訊息傳送至主題,並擷取特定訂用帳戶的訊息。

請在 Azure Cloud Shell 中執行下列命令,以確定自己使用正確的目錄:

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

撰寫程式碼以將訊息傳送至主題

若要完成能傳送銷售績效相關訊息的元件,請完成下列步驟:

  1. 在 Azure Cloud Shell 編輯器中,開啟 performancemessagesender/Program.cs 並尋找下列程式碼行:

    const string ServiceBusConnectionString = "";
    

    在引號之間貼上您在上個練習中儲存的連接字串。

  2. 如果您使用與 salesperformancemessages 不同的名稱作為佇列名稱,請更新程式碼中的 TopicName 屬性值:

    const string TopicName = "salesperformancemessages";
    
  3. 尋找 SendPerformanceMessageAsync() 方法。 (提示:其位於或接近第 26 行) 在該方法內,尋找下列程式碼:

    // Create a Service Bus client here
    

    以這行程式碼取代該行程式碼:

    // By leveraging "await using", the DisposeAsync method will be called automatically when the client variable goes out of scope.
    // In more realistic scenarios, you would store off a class reference to the client (rather than to a local variable) so that it can be used throughout your program.
    await using var client = new ServiceBusClient(ServiceBusConnectionString);
    
  4. SendPerformanceMessageAsync() 方法內尋找下列程式碼:

    // Create a sender here
    

    以這行程式碼取代該行程式碼:

    await using ServiceBusSender sender = client.CreateSender(TopicName);
    
  5. try...catch 區塊中,尋找下列程式碼:

    // Create and send a message here
    

    以這行程式碼取代該行程式碼:

    string messageBody = "Total sales for Brazil in August: $13m.";
    var message = new ServiceBusMessage(messageBody);
    
  6. 若要在主控台中顯示訊息,請在下一行插入下列程式碼:

    Console.WriteLine($"Sending message: {messageBody}");
    
  7. 若要將訊息傳送到主題,請在下一行插入下列程式碼:

    await sender.SendMessageAsync(message);
    
  8. 檢查您的最終程式碼是否類似於下列範例:

    using System;
    using System.Threading.Tasks;
    using Azure.Messaging.ServiceBus;
    
    namespace performancemessagesender
    {
        class Program
        {
            const string ServiceBusConnectionString = "Endpoint=sb://example.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxx";
            const string TopicName = "salesperformancemessages";
    
            static void Main(string[] args)
            {
                Console.WriteLine("Sending a message to the Sales Performance topic...");
                SendPerformanceMessageAsync().GetAwaiter().GetResult();
                Console.WriteLine("Message was sent successfully.");
            }
    
            static async Task SendPerformanceMessageAsync()
            {
                // 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 store off a class reference to the client (rather than to a local variable) so that it can be used throughout your program.
                await using var client = new ServiceBusClient(ServiceBusConnectionString);
    
                await using ServiceBusSender sender = client.CreateSender(TopicName);
    
                try
                {
                    string messageBody = "Total sales for Brazil in August: $13m.";
                    var message = new ServiceBusMessage(messageBody);
                    Console.WriteLine($"Sending message: {messageBody}");
                    await sender.SendMessageAsync(message);
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"{DateTime.Now} :: Exception: {exception.Message}");
                }
            }
        }
    }
    
  9. 若要儲存變更,請選取 Ctrl+S,然後選取 Ctrl+Q 以關閉編輯器。

將訊息傳送至主題

  1. 若要執行可傳送銷售相關訊息的元件,請在 Cloud Shell 中執行下列命令︰

    dotnet run --project performancemessagesender
    
  2. 當程式執行時,請監看 Cloud Shell 中指出正在傳送訊息的通知。 每次執行應用程式時,都會將另一則訊息新增至主題,而且每個訂用帳戶都會有一個複本可供使用。

    Sending a message to the Sales Performance topic...
    Sending message: Total sales for Brazil in August: $13m.
    Message was sent successfully.
    

先檢查訊息計數,然後再擷取訂用帳戶的訊息

當您看到 Message was sent successfully 時,請執行下列命令來查看 Americas 訂用帳戶中有多少訊息。 請記得以您的服務匯流排命名空間取代 <namespace-name>。

az servicebus topic subscription show \
    --resource-group "<rgn>[sandbox resource group name]</rgn>" \
    --topic-name salesperformancemessages \
    --name Americas \
    --query messageCount \
    --namespace-name <namespace-name>

如果您將 Americas 取代為 EuropeAndAsia,然後再次執行命令,您將會看到這兩個訂用帳戶都有相同的訊息數目。

撰寫程式碼以擷取訂用帳戶的主題訊息

若要建立能擷取銷售績效相關訊息的元件,請完成下列步驟:

  1. 執行 code . 以啟動編輯器。

  2. 在編輯器中,開啟 performancemessagereceiver/Program.cs 並尋找下列程式碼:

    const string ServiceBusConnectionString = "";
    

    在引號之間貼上您在上個練習中儲存的連接字串。

  3. 若要建立服務匯流排用戶端,請尋找 MainAsync() 方法。 在該方法中,找出下列程式碼行:

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

    將該程式碼取代為此行:

    var client = new ServiceBusClient(ServiceBusConnectionString);
    
  4. 若要設定訊息處理選項,請尋找下列程式碼:

    // Create the options to use for configuring the processor
    

    將該程式碼取代為此行:

    var processorOptions = new ServiceBusProcessorOptions
    {
        MaxConcurrentCalls = 1,
        AutoCompleteMessages = false
    };
    
  5. 若要建立處理器,請尋找下列程式碼:

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

    將該程式碼取代為此行:

    ServiceBusProcessor processor = client.CreateProcessor(TopicName, SubscriptionName, processorOptions);
    
  6. 若要設定處理常式,請尋找下列程式碼:

    // Configure the message and error handler to use
    

    將該程式碼取代為此行:

    processor.ProcessMessageAsync += MessageHandler;
    processor.ProcessErrorAsync += ErrorHandler;
    
  7. 若要開始處理,請尋找下列程式碼:

    // Start processing
    

    將該程式碼取代為此行:

    await processor.StartProcessingAsync();
    
  8. 尋找以下這行程式碼:

    // Since we didn't use the "await using" syntax here, we need to explicitly dispose the processor and client    
    

    將該行取代為此程式碼:

    await processor.DisposeAsync();
    await client.DisposeAsync();    
    
  9. 若要在主控台中顯示內送郵件,請尋找 MessageHandler() 方法。 您已登錄此方法來處理傳入訊息。

    將該方法內的所有程式碼取代為下列程式碼:

    Console.WriteLine($"Received message: SequenceNumber:{args.Message.SequenceNumber} Body:{args.Message.Body}");
    
  10. 若要從訂用帳戶中移除已接收的訊息,請在下一行中新增下列程式碼:

    await args.CompleteMessageAsync(args.Message);
    
  11. 檢查您的最終程式碼是否類似於下列範例:

    using System;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using Azure.Messaging.ServiceBus;
    
    namespace performancemessagereceiver
    {
        class Program
        {
            const string ServiceBusConnectionString = "Endpoint=sb://alexgeddyneil.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxx";
            const string TopicName = "salesperformancemessages";
            const string SubscriptionName = "Americas";
    
            static void Main(string[] args)
            {
                MainAsync().GetAwaiter().GetResult();
            }
    
            static async Task MainAsync()
            {
                var client = new ServiceBusClient(ServiceBusConnectionString);
    
                Console.WriteLine("======================================================");
                Console.WriteLine("Press ENTER key to exit after receiving all the messages.");
                Console.WriteLine("======================================================");
    
                var processorOptions = new ServiceBusProcessorOptions
                {
                    MaxConcurrentCalls = 1,
                    AutoCompleteMessages = false
                };
    
                ServiceBusProcessor processor = client.CreateProcessor(TopicName, SubscriptionName, processorOptions);
    
                processor.ProcessMessageAsync += MessageHandler;
                processor.ProcessErrorAsync += ErrorHandler;
    
                await processor.StartProcessingAsync();
    
                Console.Read();
    
                await processor.DisposeAsync();
                await client.DisposeAsync();
            }
    
            static async Task MessageHandler(ProcessMessageEventArgs args)
            {
                Console.WriteLine($"Received message: SequenceNumber:{args.Message.SequenceNumber} Body:{args.Message.Body}");
                await args.CompleteMessageAsync(args.Message);
            }
    
            static Task ErrorHandler(ProcessErrorEventArgs args)
            {
                Console.WriteLine($"Message handler encountered an exception {args.Exception}.");
                Console.WriteLine("Exception context for troubleshooting:");
                Console.WriteLine($"- Endpoint: {args.FullyQualifiedNamespace}");
                Console.WriteLine($"- Entity Path: {args.EntityPath}");
                Console.WriteLine($"- Executing Action: {args.ErrorSource}");
                return Task.CompletedTask;
            }
        }
    }
    
  12. 若要儲存變更,請選取 Ctrl+S,然後選取 Ctrl+Q 以關閉編輯器。

擷取訂用帳戶的主題訊息

  1. 若要執行可擷取訂用帳戶銷售績效相關訊息的元件,請執行下列命令:

    dotnet run --project performancemessagereceiver
    

    您會看到類似於下列範例的輸出:

    Received message: SequenceNumber:1 Body:Total sales for Brazil in August: $13m.
    
  2. 當程式列傳回正在接收訊息的通知後,請按 Enter 停止應用程式。

擷取訂用帳戶的訊息之後,請檢查訊息計數

執行下列命令,確認 Americas 訂用帳戶中未剩下任何訊息。 請務必以您的服務匯流排命名空間取代 <namespace-name>。

az servicebus topic subscription show \
     --resource-group "<rgn>[sandbox resource group name]</rgn>" \
     --topic-name salesperformancemessages \
     --name Americas \
     --query messageCount \
     --namespace-name <namespace-name> 

如果您將此程式碼中的 Americas 取代為 EuropeAndAsia,以查看 EuropeAndAsia 訂用帳戶的目前訊息計數,您會看到訊息計數為 1。 在上述程式碼中,僅 Americas 設定為擷取主題訊息,因此訊息仍在等候 EuropeAndAsia 加以擷取。