演習 - キューを使用してメッセージを送受信する
販売担当者が使用しているモバイル アプリと、Azure SQL Database インスタンスに各販売に関する詳細情報を格納する、Azure でホストされた Web サービスとの間で、Service Bus キューを使用して、個々の販売に関するメッセージを処理することを選択しました。
前の演習では、Azure サブスクリプションに必要なオブジェクトを実装しました。 ここでは、そのキューにメッセージを送信したり、キューからメッセージを取得したりするコードを記述します。
このユニットでは、2 つのコンソール アプリケーションをビルドします。1 つのアプリケーションはメッセージを Service Bus キューに入れ、もう 1 つのアプリケーションはメッセージを Service Bus キューから取得します。 これらのアプリケーションは、単一の .NET Core ソリューションの一部です。
Service Bus 名前空間への接続文字列を取得する
Service Bus 名前空間にアクセスし、その名前空間内でキューを使用するには、2 つのコンソール アプリで次の 2 つの情報を構成する必要があります。
- 名前空間のエンドポイント
- 認証のための共有アクセス キー
これらの値は、接続文字列から取得できます。
右側にある Azure Cloud Shell で次のコマンドを実行します。
<namespace-name>
は、前の演習で作成した Service Bus 名前空間に置き換えます。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>
応答の最後の行が接続文字列です。これには、名前空間のエンドポイントと共有アクセス キーが含まれます。 次の例のようになるはずです。
Endpoint=sb://example.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxxxx
Cloud Shell から接続文字列をコピーします。 この接続文字列はこのモジュールを通して複数回必要になるため、すぐ使用できる場所に保存してください。
スターター アプリケーションを複製して開く
Note
わかりやすくするため、以下のタスクでは、両方のコンソール アプリケーションの Program.cs ファイルに接続文字列をハード コーディングするように説明しています。 運用アプリケーションでは、接続文字列の格納には構成ファイルまたは Azure Key Vault を使用します。
Cloud Shell で次のコマンドを実行して、Git プロジェクト ソリューションをクローンします。
cd ~ git clone https://github.com/MicrosoftDocs/mslearn-connect-services-together.git
次のコマンドを実行して、クローンしたプロジェクトの start フォルダーに移動し、Cloud Shell エディターを開きます。
cd ~/mslearn-connect-services-together/implement-message-workflows-with-service-bus/src/start code .
キューにメッセージを送信するコードを記述する
Cloud Shell エディターで、privatemessagesender/Program.cs を開き、次のコード行を見つけます。
const string ServiceBusConnectionString = "";
接続文字列を引用符の間に貼り付けます。
キュー名に salesmessages とは異なる名前を使用した場合は、コード内の
QueueName
プロパティの値を更新します。const string QueueName = "salesmessages";
販売に関するメッセージを送信するコンポーネントを完成させるには、非同期操作が完了するまで非同期メソッドの評価を中断する
await
演算子を追加する必要があります。SendSalesMessageAsync()
メソッドを見つけます。 そのメソッド内で、次のコード行を見つけます。// Create a Service Bus client here
そのコード行を次のコードに置き換えます。
// 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);
SendSalesMessageAsync()
メソッド内で、次のコード行を見つけます。// Create a sender here
そのコメントを次のコードに置き換えます。
await using ServiceBusSender sender = client.CreateSender(QueueName);
try...catch
ブロック内で、次のコード行を見つけます。// Create and send a message here
そのコード行を次のコード行に置き換えます。
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);
送信側とクライアントのオブジェクトを破棄するには、ファイルの末尾近くにある次のコメントを見つけます。
// Close the connection to the sender here
この行を次のコードに置き換えます。
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(); }
privatemessagesender/Program.cs の最終的なコードが次の例のようになっていることを確認します。
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(); } } } }
変更を保存するには、Ctrl + S キーを押します。また、エディターを閉じるには、Ctrl + Q キーを押します。
メッセージをキューに送信する
Cloud Shell で次のコマンドを実行して、販売に関するメッセージを送信します。 最初の行で確実に正しいパスを表示します。
cd ~/mslearn-connect-services-together/implement-message-workflows-with-service-bus/src/start dotnet run --project ./privatemessagesender
Note
この演習でのアプリの初回実行時に、
dotnet
でリモート ソースからパッケージを復元し、アプリをビルドします。プログラムが実行されると、アプリがメッセージを送信中であることを示すメッセージがコンソールに出力されます。
Sending a message to the Sales Messages queue... Sending message: $10,000 order for bicycle parts from retailer Adventure Works. Message was sent successfully.
アプリが完了したら、次のコマンドを実行します。<namespace-name> は、Service Bus 名前空間の名前に置き換えてください。 このコマンドは、キューに入っているメッセージの数を返します。
az servicebus queue show \ --resource-group <rgn>[sandbox resource group name]</rgn> \ --name salesmessages \ --query messageCount \ --namespace-name <namespace-name>
ステップ 1 の
dotnet run
コマンドをもう一度実行してから、servicebus queue show
コマンドをもう一度実行します。 dotnet アプリを実行するたびに、新しいメッセージがキューに追加されます。 Azure コマンドを実行するたびに、messageCount
が増加することがわかります。
キューからメッセージを受信するコードの作成
次のコマンドを入力して、もう一度エディターを開きます。
code .
エディターで、privatemessagereceiver/Program.cs を開き、次のコード行を見つけます。
const string ServiceBusConnectionString = "";
引用符の間に、先に保存した接続文字列を貼り付けます。
ReceiveSalesMessageAsync()
メソッドを見つけます。 そのメソッド内で、次のコード行を見つけます。// Create a Service Bus client that will authenticate using a connection string
この行を次のコードに置き換えます。
var client = new ServiceBusClient(ServiceBusConnectionString);
メッセージ処理オプションを構成するには、次のコード行を見つけます。
// Create the options to use for configuring the processor
その行を次のコード行に置き換えます。
var processorOptions = new ServiceBusProcessorOptions { MaxConcurrentCalls = 1, AutoCompleteMessages = false };
プロセッサを作成するには、次のコード行を見つけます。
// Create a processor that we can use to process the messages
この行を次のコードに置き換えます。
await using ServiceBusProcessor processor = client.CreateProcessor(QueueName, processorOptions);
ハンドラーを構成するには、次のコード行を見つけます。
// Configure the message and error handler to use
この行を次のコードに置き換えます。
processor.ProcessMessageAsync += MessageHandler; processor.ProcessErrorAsync += ErrorHandler;
処理を開始するには、次のコード行を見つけます。
// Start processing
この行を次のコードに置き換えます。
await processor.StartProcessingAsync();
Service Bus への接続を閉じるには、次のコード行を見つけます。
// Close the processor here
この行を次のコードに置き換えます。
await processor.CloseAsync();
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); }
ErrorHandler
メソッドのコードを確認します。// handle any errors when receiving messages static Task ErrorHandler(ProcessErrorEventArgs args) { // print the exception message Console.WriteLine(args.Exception.ToString()); return Task.CompletedTask; }
privatemessagereceiver/Program.cs の最終的なコードが次の例のようになっていることを確認します。
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; } } }
変更を保存するには、Ctrl + S キーを押します。また、エディターを閉じるには、Ctrl + Q キーを押します。
キューからメッセージを受信する
販売に関するメッセージを受信するコンポーネントを実行するには、Cloud Shell で次のコマンドを実行します。
dotnet run --project privatemessagereceiver
Cloud Shell で通知を確認します。 Azure portal で Service Bus 名前空間に移動し、[メッセージ] グラフを確認します。
Received: $10,000 order for bicycle parts from retailer Adventure Works.
Cloud Shell でメッセージが受信されたことを確認したら、Enter キーを押してアプリを停止します。
メッセージ数を調べる
以下のコードを実行して、すべてのメッセージがキューから削除されたことを確認します。<namespace-name> は、必ず Service Bus 名前空間に置き換えてください。
az servicebus queue show \
--resource-group <rgn>[sandbox resource group name]</rgn> \
--name salesmessages \
--query messageCount \
--namespace-name <namespace-name>
すべてのメッセージが削除されている場合、出力は 0
となります。
個々の販売に関するメッセージを Service Bus キューに送信するコードを記述しました。 営業部門の分散アプリケーションでは、販売担当者がデバイスで使用するモバイル アプリにこのコードを記述する必要があります。
Service Bus キューからメッセージを受信するコードも記述しました。 営業部門の分散アプリケーションでは、Azure で実行されて受信メッセージを処理する Web サービスにこのコードを記述する必要があります。