エンタープライズ環境のプッシュ アーキテクチャに関するガイダンス

今日の企業における重要事項は、外部のエンド ユーザーや社内の従業員向けのモバイル アプリケーションを作成することへと徐々に変化してきました。 そこには、メインフレームや一部の LOB アプリケーションなどの既存のバックエンド システムが存在しますが、これらをモバイル アプリケーション アーキテクチャに統合する必要があります。 このガイドでは、一般的なシナリオに対する可能性のあるソリューションを推奨しながら、この統合を実行するための最適な方法について説明します。

必要となるのは、バックエンド システムで特定のイベントが発生した場合に、ユーザーのモバイル アプリケーションにプッシュ通知が送信されるようにすることです。 たとえば、iPhone 上で銀行のバンキング アプリを使用している銀行の顧客が、口座から一定金額以上の引き落としがあったときに通知を受信したいと考えている場合や、Windows Phone 上で予算承認アプリを使用している財務部門の従業員が、承認の要求が受信されたときに通知を受信したいと考えているイントラネットのシナリオがあります。

銀行口座または承認処理は、ユーザーへのプッシュを開始する必要のある何らかのバックエンド システムで実行されている可能性があります。 このようなバックエンド システムは複数存在する可能性があり、これらのすべてで、イベントが通知をトリガーしたときにプッシュを行う同じ種類のロジックを構築する必要があります。 ここでの複雑さは、複数のバックエンド システムをまとめて、エンド ユーザーがさまざまな通知にサブスクライブし、かつ複数のモバイル アプリケーションが存在する可能性のある 1 つのプッシュ システムと統合することにあります。 たとえば、このような複数のバックエンド システムからの通知を 1 つのモバイル アプリケーションで受信する可能性のあるイントラネット モバイル アプリがあります。 バックエンド システムはプッシュのセマンティクスやテクノロジを認識していないか、または認識する必要がないため、ここでの従来からの一般的なソリューションでは、目的のイベントがないかどうかバックエンド システムをポーリングし、クライアントにプッシュ メッセージを送信する役割を果たすコンポーネントが導入されていました。

より優れたソリューションとして、複雑さを軽減しながら、ソリューションをスケーラブルにする Azure Service Bus トピック/サブスクリプション モデルの使用があります。

次のセクションでは、このソリューションの全般的なアーキテクチャを紹介します (概論として、複数のモバイル アプリを前提としていますが、モバイル アプリが 1 つしかない場合にも同様に該当します)。

Architecture

Diagram of the enterprise architecture showing the flow through Events, Subscriptions, and Push Messages.

このアーキテクチャ図の重要な部分は、トピック/サブスクリプション プログラミング モデルを提供する Azure Service Bus です (詳細については、Service Bus Pub/Sub programming (Service Bus のトピックとサブスクリプションの使用方法) (Service Bus のトピックとサブスクリプションの使用方法)に関するページを参照)。 受信者 (この場合は、モバイル バックエンド。通常は、モバイル アプリへのプッシュを開始する Azure Mobile Service) は、バックエンド システムから直接にではなく、代わりに、Azure Service Bus によって提供される中間の抽象化レイヤーからメッセージを受信します。これにより、モバイル バックエンドは 1 つ以上のバックエンド システムからメッセージを受信できるようになります。 Service Bus トピックは、バックエンド システムごとに作成する必要があります (会計、人事、財務など)。これは基本的に、メッセージのプッシュ通知としての送信を開始する、対象の "トピック" です。 バックエンド システムは、これらのトピックにメッセージを送信します。 Service Bus のサブスクリプションを作成することで、モバイル バックエンドがこのような 1 つまたは複数のトピックをサブスクライブできます。 これにより、モバイル バックエンドは対応するバックエンド システムから通知を受信できます。 モバイル バックエンドは継続的にサブスクリプションのメッセージをリッスンし、メッセージを受信すると、Notification Hubs に通知として送信します。 その後、通知ハブは最終的に、そのメッセージをモバイル アプリに配信します。 主要なコンポーネントの一覧を次に示します。

  1. バックエンド システム (LoB またはレガシ システム)
    • Service Bus のトピックを作成
    • メッセージを送信
  2. モバイル バックエンド
    • サービスのサブスクリプションを作成
    • (バックエンド システムから) メッセージを受信
    • (Azure Notification Hubs 経由で) クライアントに通知を送信
  3. モバイル アプリケーション
    • 通知を受信して表示

メリット

  1. 受信者 (Notification Hubs を経由したモバイル アプリケーションまたはサービス) と送信者 (バックエンド システム) を分離することで、最小限の変更によって追加のバックエンド システムを統合できます。
  2. これはまた、複数のモバイル アプリのシナリオで、1 つ以上のバックエンド システムからイベントを受信できるようにします。

サンプル

前提条件

これらの概念や一般的な作成および構成手順に精通するために、次のチュートリアルを完了してください。

  1. Service Bus パブリッシュ/サブスクライブ プログラミング - このチュートリアルでは、Service Bus トピック/サブスクリプションの操作の詳細、トピック/サブスクリプションを格納する名前空間を作成する方法、そこからメッセージを送受信する方法について説明します。
  2. Notification Hubs の使用 - Windows ユニバーサル チュートリアル - このチュートリアルでは、Windows ストア アプリを設定し、Notification Hubs を使用して登録してから通知を受信する方法について説明します。

サンプル コード

完全なコード サンプルは「 Notification Hubs のサンプル (英語)」から入手できます。 このサンプルは、3 つのコンポーネントに分割されています。

  1. EnterprisePushBackendSystem

    a. このプロジェクトは Azure.Messaging.ServiceBus NuGet パッケージを使用し、「Service Bus パブリッシュ/サブスクライブ プログラミング」に基づいています。

    b. このアプリケーションは、LoB システムをシミュレートする単純な C# コンソール アプリであり、メッセージのモバイル アプリへの配信を開始します。

    static async Task Main(string[] args)
    {
        string connectionString =
            ConfigurationManager.AppSettings.Get("Azure.ServiceBus.ConnectionString");
    
        // Create the topic
        await CreateTopicAsync(connectionString);
    
        // Send message
        await SendMessageAsync(connectionString);
    }
    

    c. CreateTopicAsync は、Service Bus トピックを作成するために使用されます。

    public static async Task CreateTopicAsync(string connectionString)
    {
        // Create the topic if it does not exist already
        ServiceBusAdministrationClient client = new ServiceBusAdministrationClient(connectionString);
    
        if (!await client.TopicExistsAsync(topicName))
        {
            await client.CreateTopicAsync(topicName);
        }
    }
    

    d. SendMessageAsync は、この Service Bus のトピックにメッセージを送信するために使用します。 このコードは単純に、このサンプルの目的として、一連のランダムなメッセージを定期的にトピックに送信します。 通常は、イベントの発生時にメッセージを送信するバックエンド システムが存在します。

    public static sync Task SendMessageAsync(string connectionString)
    {
        await using var client = new ServiceBusClient(connectionString);
        ServiceBusSender sender = client.CreateSender(topicName);
    
        // Sends random messages every 10 seconds to the topic
        string[] messages =
        {
            "Employee Id '{0}' has joined.",
            "Employee Id '{0}' has left.",
            "Employee Id '{0}' has switched to a different team."
        };
    
        while (true)
        {
            Random rnd = new Random();
            string employeeId = rnd.Next(10000, 99999).ToString();
            string notification = String.Format(messages[rnd.Next(0,messages.Length)], employeeId);
    
            // Send Notification
            ServiceBusMessage message = new ServiceBusMessage(notification);
            await sender.SendMessageAsync(message);
    
            Console.WriteLine("{0} Message sent - '{1}'", DateTime.Now, notification);
    
            System.Threading.Thread.Sleep(new TimeSpan(0, 0, 10));
        }
    }
    
  2. ReceiveAndSendNotification

    a. このプロジェクトは Azure.Messaging.ServiceBus および Microsoft.Web.WebJobs.Publish NuGet パッケージを使用し、「Service Bus パブリッシュ/サブスクライブ プログラミング」に基づいています。

    b. 次のコンソール アプリは、LoB/バックエンド システム メッセージをリッスンするために継続的に実行する必要があるため、Azure WebJob として実行されます。 このアプリケーションは、モバイル バックエンドの一部です。

    static async Task Main(string[] args)
    {
        string connectionString =
                 ConfigurationManager.AppSettings.Get("Azure.ServiceBus.ConnectionString");
    
        // Create the subscription that receives messages
        await CreateSubscriptionAsync(connectionString);
    
        // Receive message
        await ReceiveMessageAndSendNotificationAsync(connectionString);
    }
    

    c. CreateSubscriptionAsync は、バックエンド システムがメッセージを送信するトピックの Service Bus サブスクリプションを作成するために使用されます。 ビジネス シナリオに応じて、このコンポーネントは対応するトピックへの 1 つ以上のサブスクリプションを作成します (たとえば、一部は人事システムから、また一部は財務システムからメッセージを受信するなど)。

    static async Task CreateSubscriptionAsync(string connectionString)
    {
        // Create the subscription if it does not exist already
        ServiceBusAdministrationClient client = new ServiceBusAdministrationClient(connectionString);
    
        if (!await client.SubscriptionExistsAsync(topicName, subscriptionName))
        {
            await client.CreateSubscriptionAsync(topicName, subscriptionName);
        }
    }
    

    d. ReceiveMessageAndSendNotificationAsync は、サブスクリプションを使用してトピックからメッセージを読み取り、読み取りが正常に実行された場合に、Azure Notification Hubs を使用してモバイル アプリケーションに送信する通知 (サンプル シナリオでは Windows ネイティブのトースト通知) を作成するために使用します。

    static async Task ReceiveMessageAndSendNotificationAsync(string connectionString)
    {
        // Initialize the Notification Hub
        string hubConnectionString = ConfigurationManager.AppSettings.Get
                ("Microsoft.NotificationHub.ConnectionString");
        hub = NotificationHubClient.CreateClientFromConnectionString
                (hubConnectionString, "enterprisepushservicehub");
    
        ServiceBusClient Client = new ServiceBusClient(connectionString);
        ServiceBusReceiver receiver = Client.CreateReceiver(topicName, subscriptionName);
    
        // Continuously process messages received from the subscription
        while (true)
        {
            ServiceBusReceivedMessage message = await receiver.ReceiveMessageAsync();
            var toastMessage = @"<toast><visual><binding template=""ToastText01""><text id=""1"">{messagepayload}</text></binding></visual></toast>";
    
            if (message != null)
            {
                try
                {
                    Console.WriteLine(message.MessageId);
                    Console.WriteLine(message.SequenceNumber);
                    string messageBody = message.Body.ToString();
                    Console.WriteLine("Body: " + messageBody + "\n");
    
                    toastMessage = toastMessage.Replace("{messagepayload}", messageBody);
                    SendNotificationAsync(toastMessage);
    
                    // Remove message from subscription
                    await receiver.CompleteMessageAsync(message);
                }
                catch (Exception)
                {
                    // Indicate a problem, unlock message in subscription
                    await receiver.AbandonMessageAsync(message);
                }
            }
        }
    }
    static async void SendNotificationAsync(string message)
    {
        await hub.SendWindowsNativeNotificationAsync(message);
    }
    

    e. このアプリを WebJob として発行するには、Visual Studio でソリューションを右クリックし、 [WebJob として発行] を選択します。

    Screenshot of the right-click options being displayed with Publish as Azure WebJob outlined in red.

    f. 発行プロファイルを選択し、この WebJob をホストする新しい Azure Web サイトを作成し (このサイトがまだ存在しない場合)、Web サイトを作成したら [発行] を選択します。

    Screenshot showing the workflow to create a site on Azure.

    [Web の発行] ダイアログのスクリーンショット。[Microsoft Azure Web サイト] オプションが選択されています。緑の矢印が指し示す [Select Existing Website](既存の Web サイトを選択する) ダイアログ ボックスでは [新規] オプションが赤で囲まれています。そこからさらに緑の矢印が指し示す [Create site on Microsoft Azure](Microsoft Azure でサイトを作成する) ダイアログ ボックスでは [サイト名] と [作成] オプションが赤で囲まれています。

    g. ジョブを [連続実行する] ように構成すると、Azure Portal にログインしたときに、以下のような画面が表示されます。

    Screenshot of the Azure Portal with the enterprise push backend webjobs displayed and the Name, Schedule, and Logs values outlined in red.

  3. EnterprisePushMobileApp

    a. このアプリケーションは、モバイル バックエンドの一部として実行されている WebJob からトースト通知を受信して表示する Windows ストア アプリケーションです。 このコードは、「Notification Hubs の使用 - Windows ユニバーサル チュートリアル」に基づいています。

    b. アプリケーションでトースト通知の受信が有効になっていることを確認します。

    c. (HubName および DefaultListenSharedAccessSignature の値を置換してから) アプリの起動時に、以下の Notification Hubs の登録コードが確実に呼び出されるようにします。

    private async void InitNotificationsAsync()
    {
        var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
    
        var hub = new NotificationHub("[HubName]", "[DefaultListenSharedAccessSignature]");
        var result = await hub.RegisterNativeAsync(channel.Uri);
    
        // Displays the registration ID so you know it was successful
        if (result.RegistrationId != null)
        {
            var dialog = new MessageDialog("Registration successful: " + result.RegistrationId);
            dialog.Commands.Add(new UICommand("OK"));
            await dialog.ShowAsync();
        }
    }
    

サンプルの実行

  1. WebJob が正常に実行され、継続的に実行するようにスケジュールされていることを確認します。

  2. Windows ストア アプリを起動する EnterprisePushMobileApp を実行します。

  3. LoB バックエンドをシミュレートし、メッセージの送信を開始する EnterprisePushBackendSystem コンソール アプリケーションを実行すると、次の図のようなトースト通知が表示されます。

    Screenshot of a console running the Enterprise Push Backend System app and the message that is sent by the app.

  4. これらのメッセージは最初、WebJob で Service Bus サブスクリプションによって監視されていた Service Bus トピックに送信されました。 メッセージを受信すると、通知が作成されてモバイル アプリに送信されます。 Azure Portal で WebJobs の [ログ] リンクをクリックすると、WebJobs ログで処理を確認することができます。

    Screenshot of the Continuous WebJob Details dialog box with the message that is sent outlined in red.