Azure Service Bus キューを使用する .NET 多層アプリケーション
Microsoft Azure 向けアプリケーションは、Visual Studio および無料の Azure SDK for .NET を使用して簡単に開発できます。 このチュートリアルでは、ローカル環境で実行されている複数の Azure リソースを使用するアプリケーションを作成する手順について説明します。
次のことについて説明します。
- 1 回のダウンロードとインストールで、Azure 開発用に コンピューターを準備する方法
- Azure 開発のための Visual Studio の使用方法
- Web ロールおよび Worker ロールを使用して Azure に 多層アプリケーションを作成する方法
- Service Bus キューを使用して各層間で通信する方法
注意
このチュートリアルを完了するには、Azure アカウントが必要です。 MSDN サブスクライバーの特典を有効にするか、無料アカウントにサインアップしてください。
このチュートリアルでは、Azure のクラウド サービスで多層アプリケーションを構築して実行します。 フロントエンドは ASP.NET MVC Web ロール、バックエンドは Service Bus キューを使用する worker ロールです。 同じ多層アプリケーションを作成するときに、クラウド サービスではなく Azure Web サイトにデプロイされる Web プロジェクトとしてフロントエンドを実装することもできます。 また、.NET オンプレミス/クラウド ハイブリッド アプリケーションのチュートリアルを試すこともできます。
次に示すのは完成したアプリケーションのスクリーンショットです。
シナリオの概要: ロール間通信
処理を要求するため、Web ロールで実行されているフロントエンド UI コンポーネントは、worker ロールで実行されている中間層ロジックと対話する必要があります。 この例では、各層間での通信に Service Bus メッセージングが使用されています。
Web 層と中間層との間で Service Bus メッセージングを使用すると、2 つのコンポーネントの結合が解除されます。 直接メッセージング (TCP や HTTP) とは異なり、Web 層は中間層に直接接続しません。その代わりに、作業をメッセージとして Service Bus にプッシュします。Service Bus は、このメッセージを中間層が受け取り、処理する用意ができるまで確実に保持します。
Service Bus には、ブローカー メッセージングをサポートする、キューとトピックという 2 つのエンティティがあります。 キューでは、各メッセージは単一のレシーバーが使用するキューに送信されます。 トピックは発行/サブスクライブ パターンをサポートし、発行された各メッセージをトピックに登録されているサブスクリプションで使用します。 各サブスクリプションは、独自のメッセージ キューを論理的に管理しています。 また、サブスクリプションにフィルター ルールを構成し、サブスクリプション キューに渡すメッセージをフィルターに一致するメッセージのみに制限できます。 次の例では、Service Bus キューを使用します。
この通信メカニズムには、直接メッセージングと比較した場合に、次のような利点があります。
一時的な結合の解除。 非同期メッセージング パターンを使用する場合、プロデューサーとコンシューマーが同時にオンラインになっている必要はありません。 コンシューマーが メッセージを受け取る用意ができるまで、Service Bus が確実に メッセージを保持します。 このため、保守などのために、分散型アプリケーションの各コンポーネントの接続を自主的に解除できます。また、コンポーネントのクラッシュによって接続が解除されても問題なく、接続解除の際にシステム全体に影響が及ぶことがありません。 さらに、コンシューマー側アプリケーションがオンラインになっている時間は、1 日のうち一定の時間だけで済みます。
負荷の平準化。 多くのアプリケーションでは、システム負荷が時間の経過とともに変化しますが、各作業単位に必要な処理時間は通常一定に保たれます。 メッセージ プロデューサーとメッセージ コンシューマーの間をキューで仲介することは、コンシューマー側アプリケーション (worker) はピーク時ではなく平均時の負荷に対応できるようにプロビジョニングすればいいということを意味します。 キューの深さは、受信の負荷の変化に応じて増減します。 このため、アプリケーション負荷への対応に必要なインフラストラクチャの観点から直接費用を節約できます。
負荷分散。 負荷の増大に合わせて、キューからの読み取りのために worker プロセスを追加できます。 各メッセージは、ワーカー プロセスの中の 1 つのプロセスによって処理されます。 また、このプルベースの負荷分散では、各 worker マシンがそれぞれ独自の最大レートでメッセージをプルするため、worker マシンの処理能力が異なる場合であっても最適に使用できます。 このパターンは、しばしば競合コンシューマーのパターンと呼ばれます。
以降のセクションでは、このアーキテクチャを実装するコードについて説明します。
前提条件
このチュートリアルでは、Microsoft Entra 認証を使用して ServiceBusClient
と ServiceBusAdministrationClient
のオブジェクトを作成します。 また DefaultAzureCredential
を使用してこれを使用し、次の手順を実行して、アプリケーションを開発環境でローカルでテストする必要があります。
- アプリケーションを Microsoft Entra ID に登録します。
-
アプリケーションを
Service Bus Data Owner
ロールに追加します。 -
AZURE-CLIENT-ID
、AZURE-TENANT-ID
およびAZURE-CLIENT-SECRET
の環境変数を設定します。 手順については、この記事を参照してください。
Service Bus の組み込みロールの一覧については、「 Service Bus の Azure 組み込みロール」を参照してください。
名前空間の作成
最初の手順では、名前空間 を作成して、その Shared Access Signature (SAS) キーを取得します。 名前空間は、Service Bus によって公開される各アプリケーションのアプリケーション境界を提供します。 名前空間が作成された時点で、システムによって SAS キーが自動的に生成されます。 名前空間名と SAS キーの組み合わせが、アプリケーションへのアクセスを Service Bus が認証する資格情報になります。
Azure Portal での名前空間の作成
Azure の Service Bus メッセージング エンティティを使用するには、Azure 全体で一意となる名前を備えた名前空間を最初に作成しておく必要があります。 名前空間により、ご利用のアプリケーション内に Service Bus リソース (キュー、トピックなど) 用のスコープ コンテナーが提供されます。
名前空間を作成するには:
Azure portal にサインインします。
[すべてのサービス] ページに移動します。
左側のナビゲーション バーで、カテゴリの一覧から [統合] を選択し、[Service Bus] 上にマウス ポインターを置き、[Service Bus] タイルの [+] ボタンを選択します。
[名前空間の作成] ページの [基本] タブで、こちらの手順を実行します。
[サブスクリプション] で、名前空間を作成する Azure サブスクリプションを選択します。
[リソース グループ] では、既存のリソース グループを選ぶか、新しく作成します。
名前空間の名前を入力します。 名前空間名は次の名前付け規則に従う必要があります。
- この名前は Azure 全体で一意である必要があります。 その名前が使用できるかどうかがすぐに自動で確認されます。
- 名前の長さは 6 ~ 50 文字である。
- この名前には、文字、数字、ハイフン
-
のみを含めることができます。 - 名前の先頭は文字、末尾は文字または数字にする必要があります。
- 名前の末尾を
-sb
または-mgmt
にすることはできません。
[場所] で、名前空間をホストするリージョンを選択します。
[価格レベル] で、名前空間の価格レベル (Basic、Standard、Premium) を選択します。 このクイック スタートでは、 [Standard] を選択します。
Premium レベルを選んだ場合は、名前空間の geo レプリケーションを有効にできるかどうかを選びます。 geo レプリケーション機能を使用すると、名前空間のメタデータとデータが、プライマリ Azure リージョンから 1 つ以上のセカンダリ Azure リージョンに、継続的にレプリケートされることが保証されます。
重要
トピックとサブスクリプションを使用する場合は、Standard または Premium を選択してください。 Basic 価格レベルでは、トピックとサブスクリプションはサポートされていません。
[Premium] 価格レベルを選択した場合は、メッセージング ユニットの数を指定します。 Premium レベルでは、各ワークロードが分離した状態で実行されるように、CPU とメモリのレベルでリソースが分離されます。 このリソースのコンテナーをメッセージング ユニットと呼びます。 Premium 名前空間には、少なくとも 1 つのメッセージング ユニットがあります。 Service Bus の Premium 名前空間ごとに、1 個、2 個、4 個、8 個、または 16 個のメッセージング ユニットを選択できます。 詳細については、Service Bus の Premium メッセージングに関するページをご覧ください。
ページ下部にある [確認と作成] を選択します。
[確認および作成] ページで、設定を確認し、 [作成] を選択します。
リソースのデプロイが成功したら、デプロイ ページで [リソースに移動] を選択します。
Service Bus 名前空間のホーム ページが表示されます。
名前空間への接続文字列を取得する (Azure portal)
新しい名前空間を作成すると、主キーとセカンダリ キー、およびそれぞれが名前空間のすべての側面を完全に制御できるプライマリとセカンダリの接続文字列を使用して、Shared Access Signature (SAS) の初期ポリシーが自動的に生成されます。 通常の送信者と受信者を対象に、より権限を制限した規則を作成する方法については、「Service Bus の認証と承認」をご覧ください。
クライアントは、接続文字列を使用して Service Bus の名前空間に接続できます。 名前空間のプライマリ接続文字列をコピーするには、次の手順に従います。
[Service Bus 名前空間] ページで、左側のメニューの [共有アクセス ポリシー] を選択します。
[共有アクセス ポリシー] ページで、 [RootManageSharedAccessKey] を選択します。
[ポリシー: RootManageSharedAccessKey] ウィンドウで、[プライマリ接続文字列] の横にある [コピー] ボタンを選択し、後で使用するために接続文字列をクリップボードにコピーします。 この値をメモ帳などに一時的に貼り付けます。
このページを使用して、主キー、2 次キー、プライマリ接続文字列、セカンダリ接続文字列をコピーできます。
Web ロールを作成する
このセクションでは、アプリケーションのフロントエンドを作成します。 最初に、アプリケーションで表示するページを作成します。 その後、Service Bus キューに項目を送信し、キューに関するステータス情報を表示するコードを追加します。
プロジェクトを作成する
管理者特権で Visual Studio を起動します。Visual Studio のプログラム アイコンを右クリックし、[管理者として実行] を選択します。 Azure Compute Emulator (後ほどこの記事で解説) を使用するには、管理者特権で Visual Studio を開始する必要があります。
Visual Studio の [ファイル] メニューで、[新規作成]、[プロジェクト] の順に選択します。
[テンプレート] ページで、次の手順を行います。
プログラミング言語に C# を選択します。
プロジェクトの種類にクラウドを選択します。
Azure Cloud Service を選択します。
[次へ] を選択します。
プロジェクトに MultiTierApp という名前を付け、プロジェクトの場所を選択して、 [作成] を選択します。
[ロール] ページで、ASP.NET Web ロールをダブルクリックし、[OK] を選択します。
[Azure のクラウド サービス ソリューション] の [WebRole1] をポイントし、鉛筆のアイコンを選択して、Web ロールの名前を "FrontendWebRole" に変更します。 [OK] をクリックします。 (「FrontEnd」ではなく「Frontend」と入力してください。小文字の "e" です)。
[Create a new ASP.NET Web Application] (\新しい ASP.NET Web アプリケーションの作成\) ダイアログ ボックスで、[MVC] を選択し、[作成] を選択します。
ソリューション エクスプローラーで FrontendWebRole プロジェクトの [参照] を右クリックし、[NuGet パッケージの管理] を選択します。
[参照] タブをクリックして、Azure.Messaging.ServiceBus を選択します。 Azure.Messaging.ServiceBus パッケージを選択し、 [インストール] を選択して使用条件に同意します。
これで、必要なクライアント アセンブリを参照できるようになり、新しいコード ファイルがいくつか追加されました。
同じ手順に従って、
Azure.Identity
NuGet パッケージをプロジェクトに追加します。ソリューション エクスプローラーで FrontendWebRole を展開し、[モデル] を右クリックして [追加]、[クラス] の順に選択します。 [名前] ボックスに「OnlineOrder.cs」と入力します。 その後、 [追加] を選択します。
Web ロール用のコードの作成
このセクションでは、アプリケーションで表示するさまざまなページを作成します。
Visual Studio で、OnlineOrder.cs ファイルの既存の名前空間定義を、次のコードに置き換えます。
namespace FrontendWebRole.Models { public class OnlineOrder { public string Customer { get; set; } public string Product { get; set; } } }
ソリューション エクスプローラーで、[Controllers\HomeController.cs] をダブルクリックします。 次の using ステートメントを名前空間を含めるファイルの先頭に追加し、Service Bus と同様に先ほど作成したモデルの名前空間を追加します。
using FrontendWebRole.Models; using Azure.Messaging.ServiceBus;
また、Visual Studio の HomeController.cs ファイルで既存の名前空間の定義を次のコードに置き換えます。 このコードには、キューへの項目の送信を処理するメソッドが含まれています。
namespace FrontendWebRole.Controllers { public class HomeController : Controller { public ActionResult Index() { // Simply redirect to Submit, since Submit will serve as the // front page of this application. return RedirectToAction("Submit"); } public ActionResult About() { return View(); } // GET: /Home/Submit. // Controller method for a view you will create for the submission // form. public ActionResult Submit() { // Will put code for displaying queue message count here. return View(); } // POST: /Home/Submit. // Controller method for handling submissions from the submission // form. [HttpPost] // Attribute to help prevent cross-site scripting attacks and // cross-site request forgery. [ValidateAntiForgeryToken] public ActionResult Submit(OnlineOrder order) { if (ModelState.IsValid) { // Will put code for submitting to queue here. return RedirectToAction("Submit"); } else { return View(order); } } } }
[ビルド] メニューの [ソリューションのビルド] を選択して、ここまでの作業に問題がないことを確認します。
次に、前の手順で作成した
Submit()
メソッドのビューを作成します。 HomeController.cs ファイルのSubmit()
メソッド (パラメーターを受け取らないSubmit()
のオーバーロード) 内で右クリックし、 [ビューの追加] を選択します。[Add New Scaffolded Item] (新しいスキャフォールディング項目の追加) ダイアログ ボックスで、 [追加] を選びます。
[ビューの追加] ダイアログ ボックスで、次の手順を行います。
[テンプレート] ボックスの一覧から [作成] を選択します。
[モデル クラス] ボックスの一覧で OnlineOrder クラスを選択します。
[追加] を選択します。
次に、アプリケーションの表示名を変更します。 ソリューション エクスプローラーで、Views\Shared\_Layout.cshtml ファイルをダブルクリックして Visual Studio エディターで開きます。
My ASP.NET Application となっている箇所をすべて Northwind Traders Products に置き換えます。
Home、About、および Contact の各リンクを削除します。 以下の強調表示されたコードを削除してください。
最後に、キューに関する情報を表示できるように、送信ページを変更します。 ソリューション エクスプローラーで、Views\Home\Submit.cshtml ファイルをダブルクリックし、Visual Studio エディターで開きます。
<h2>Submit</h2>
という行の下に、次の行を追加します。 この時点では、ViewBag.MessageCount
は空の状態です。 この値は後で入力します。<p>Current number of orders in queue waiting to be processed: @ViewBag.MessageCount</p>
これで、UI の実装が終わりました。 F5 キーを押してアプリケーションを実行し、期待どおりに表示されることを確認します。
Service Bus キューに項目を送信するためのコードの作成
次に、項目をキューに送信するためのコードを追加します。 最初に、Service Bus キューの接続情報を含むクラスを作成します。 次に、Global.aspx.cs から接続を初期化します。 最後に、Service Bus キューに実際に項目を送信するために、HomeController.cs 内に作成してある送信用のコードを更新します。
ソリューション エクスプローラーで、FrontendWebRole を右クリックします (ロールではなくプロジェクトを右クリック)。 [追加]、[クラス] の順に選択します。
クラスに QueueConnector.cs という名前を付けます。 [追加] を選択してクラスを作成します。
接続情報をカプセル化して、Service Bus のキューへの接続を初期化するコードを追加します。 QueueConnector.cs の内容全体を次のコードに置き換え、
your Service Bus namespace
の値 (名前空間の名前) とyourKey
の値 (Azure Portal から取得したプライマリ キー) を入力します。using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Threading.Tasks; using Azure.Messaging.ServiceBus; using Azure.Messaging.ServiceBus.Administration; namespace FrontendWebRole { public static class QueueConnector { // object to send messages to a Service Bus queue internal static ServiceBusSender SBSender; // object to create a queue and get runtime properties (like message count) of queue internal static ServiceBusAdministrationClient SBAdminClient; // Fully qualified Service Bus namespace private const string FullyQualifiedNamespace = "<SERVICE BUS NAMESPACE NAME>.servicebus.windows.net"; // The name of your queue. internal const string QueueName = "OrdersQueue"; public static async Task Initialize() { // Create a Service Bus client that you can use to send or receive messages ServiceBusClient SBClient = new ServiceBusClient(FullyQualifiedNamespace, new DefaultAzureCredential()); // Create a Service Bus admin client to create queue if it doesn't exist or to get message count SBAdminClient = new ServiceBusAdministrationClient(FullyQualifiedNamespace, new DefaultAzureCredential()); // create the OrdersQueue if it doesn't exist already if (!(await SBAdminClient.QueueExistsAsync(QueueName))) { await SBAdminClient.CreateQueueAsync(QueueName); } // create a sender for the queue SBSender = SBClient.CreateSender(QueueName); } } }
次に、Initialize メソッドが呼び出されるようにします。 ソリューション エクスプローラーで、Global.asax\Global.asax.cs をダブルクリックします。
Application_Start メソッドの最後に次のコード行を追加します。
FrontendWebRole.QueueConnector.Initialize().Wait();
最後に、前の手順で作成した Web コードを更新し、項目をキューに送信します。 ソリューション エクスプローラーで、[Controllers\HomeController.cs] をダブルクリックします。
キューのメッセージ数を取得するために、
Submit()
メソッド (パラメーターを受け取らないオーバーロード) を次のように更新します。public ActionResult Submit() { QueueRuntimeProperties properties = QueueConnector.adminClient.GetQueueRuntimePropertiesAsync(QueueConnector.queueName).Result; ViewBag.MessageCount = properties.ActiveMessageCount; return View(); }
キューに注文情報を送信するために、
Submit(OnlineOrder order)
メソッド (パラメーターを 1 つ受け取るオーバーロード) を次のように更新します。public ActionResult Submit(OnlineOrder order) { if (ModelState.IsValid) { // create a message var message = new ServiceBusMessage(new BinaryData(order)); // send the message to the queue QueueConnector.sbSender.SendMessageAsync(message); return RedirectToAction("Submit"); } else { return View(order); } }
ここで再び、アプリケーションを実行します。 注文を送信するたびに、メッセージ数が増えていきます。
worker ロールを作成する
次に、送信された注文を処理する worker ロールを作成します。 この例では、Visual Studio プロジェクト テンプレートの Worker Role with Service Bus Queue を使用します。 必要な資格情報は、既にポータルから取得しています。
Visual Studio を Azure アカウントに接続していることを確認します。
Visual Studio のソリューション エクスプローラーで、MultiTierApp プロジェクト内の Roles フォルダーを右クリックします。
[追加] を選択し、[新しいワーカー ロール プロジェクト] を選択します。 [新しいロール プロジェクトの追加] ダイアログ ボックスが表示されます。
[新しいロール プロジェクトの追加] ダイアログ ボックスで、 [Worker ロール] を選択します。 レガシ Service Bus SDK を使用するコードが生成されるため、Service Bus キューを持つ Worker ロールを選択しないでください。
[名前] ボックスで、プロジェクトに OrderProcessingRole という名前を付けます。 その後、 [追加] を選択します。
ソリューション エクスプローラーで OrderProcessingRole プロジェクトを右クリックし、 [NuGet パッケージの管理...] を選びます。
[参照] タブをクリックして、Azure.Messaging.ServiceBus を選択します。 Azure.Messaging.ServiceBus パッケージを選択し、 [インストール] を選択して使用条件に同意します。
同じ手順に従って、
Azure.Identity
NuGet パッケージをプロジェクトに追加します。キューからの注文を処理するときの注文を表す OnlineOrder クラスを作成します。 作成済みのクラスを再利用できます。 ソリューション エクスプローラーで、OrderProcessingRole クラスを右クリックします (ロールではなく、クラスを右クリック)。 [追加] を選択し、[既存の項目] を選択します。
FrontendWebRole\Models のサブフォルダーに移動し、OnlineOrder.cs をダブルクリックしてこのプロジェクトに追加します。
OrderProcessingRole プロジェクトの WorkerRole.csファイルに次の
using
ステートメントを追加します。using FrontendWebRole.Models; using Azure.Messaging.ServiceBus; using Azure.Messaging.ServiceBus.Administration;
WorkerRole.cs で、次のプロパティを追加します。
重要
前提条件の一部として説明した名前空間の接続文字列を使用します。
// Fully qualified Service Bus namespace private const string FullyQualifiedNamespace = "<SERVICE BUS NAMESPACE NAME>.servicebus.windows.net"; // The name of your queue. private const string QueueName = "OrdersQueue"; // Service Bus Receiver object to receive messages message the specific queue private ServiceBusReceiver SBReceiver;
OnStart
メソッドを更新してServiceBusClient
オブジェクト、そしてServiceBusReceiver
オブジェクトを作成し、OrdersQueue
からメッセージを受信します。public override bool OnStart() { // Create a Service Bus client that you can use to send or receive messages ServiceBusClient SBClient = new ServiceBusClient(FullyQualifiedNamespace, new DefaultAzureCredential()); CreateQueue(QueueName).Wait(); // create a receiver that we can use to receive the message SBReceiver = SBClient.CreateReceiver(QueueName); return base.OnStart(); } private async Task CreateQueue(string queueName) { // Create a Service Bus admin client to create queue if it doesn't exist or to get message count ServiceBusAdministrationClient SBAdminClient = new ServiceBusAdministrationClient(FullyQualifiedNamespace, new DefaultAzureCredential()); // create the OrdersQueue if it doesn't exist already if (!(await SBAdminClient.QueueExistsAsync(queueName))) { await SBAdminClient.CreateQueueAsync(queueName); } }
メッセージを受信するコードを含める
RunAsync
メソッドを更新します。private async Task RunAsync(CancellationToken cancellationToken) { // TODO: Replace the following with your own logic. while (!cancellationToken.IsCancellationRequested) { // receive message from the queue ServiceBusReceivedMessage receivedMessage = await SBReceiver.ReceiveMessageAsync(); if (receivedMessage != null) { Trace.WriteLine("Processing", receivedMessage.SequenceNumber.ToString()); // view the message as an OnlineOrder OnlineOrder order = receivedMessage.Body.ToObjectFromJson<OnlineOrder>(); Trace.WriteLine(order.Customer + ": " + order.Product, "ProcessingMessage"); // complete message so that it's removed from the queue await SBReceiver.CompleteMessageAsync(receivedMessage); } } }
アプリケーションを完了しました。 ソリューション エクスプローラーで、MultiTierApp のプロジェクトを右クリックし、[スタートアップ プロジェクトに設定] を選択して F5 キーを押すと、完全なアプリケーションをテストできます。 worker ロールがキューの項目を処理し、完了としてマークしているため、メッセージ数は増えません。 Azure コンピューティング エミュレーターのUI を表示すると、worker ロールのトレース出力を確認できます。 これを実行するには、タスク バーの通知領域のエミュレーター アイコンを右クリックし、[Show Compute Emulator UI (コンピューティング エミュレーター UI の表示)] をクリックします。
次の手順
Service Bus の詳細については、次のリソースを参照してください。