チュートリアル:Azure Notification Hubs を使用して特定のユーザーに通知を送信する

概要

このチュートリアルでは、Azure Notification Hubs を使用して特定のデバイスで特定のアプリケーション ユーザーにプッシュ通知を送信する方法について説明します。 クライアントを認証するために ASP.NET WebAPI バックエンドが使用されます。 バックエンドは、クライアント アプリケーション ユーザーを認証すると、通知の登録にタグを自動的に追加します。 バックエンドは、このタグを使用して特定のユーザーに通知を送信します。

注意

このチュートリアルの完成したコードは、GitHub にあります。

このチュートリアルでは、次の手順を実行します。

  • Web API プロジェクトを作成する
  • WebAPI バックエンドに対してクライアントを認証する
  • WebAPI バックエンドを使用して通知に登録する
  • WebAPI バックエンドから通知を送信する
  • 新しい WebAPI バックエンドを発行する
  • クライアント プロジェクトのコードを更新する
  • アプリケーションをテストする

前提条件

このチュートリアルは、「チュートリアル: Azure Notification Hubs を使用してユニバーサル Windows プラットフォーム アプリに通知を送信する」のチュートリアルで完成したプロジェクト内のコードを更新します。 そのため、このチュートリアルを開始する前に、それを完了してください。

注意

バックエンド サービスとして Azure App Service で Mobile Apps を使用している場合は、このチュートリアルの Mobile Apps バージョンに関するページをご覧ください。

Web API プロジェクトを作成する

次のセクションでは、新しい ASP.NET WebAPI バックエンドの作成について説明します。 このプロセスには、主に次の 3 つの目的があります。

  • クライアントの認証: クライアント要求を認証し、ユーザーを要求と関連付けるメッセージ ハンドラーを追加します。
  • WebAPI バックエンドを使用した通知の登録: クライアント デバイスで通知を受信するための新しい登録を処理するコントローラーを追加します。 認証されたユーザー名はタグとして自動的に登録に追加されます。
  • クライアントへの通知の送信: ユーザーがタグに関連するデバイスやクライアントにセキュリティで保護されたプッシュ通知をトリガーできるコントローラーを追加します。

次の操作を実行して、新しい ASP.NET Core 6.0 Web API バックエンドを作成します。

確認するには、Visual Studio を起動します。 [ツール] メニューの [拡張機能と更新プログラム] を選びます。 お使いの Visual Studio に対応した NuGet パッケージ マネージャーを探し、バージョンが最新であることを確認します。 最新バージョンでない場合は、アンインストールして、NuGet パッケージ マネージャーを再インストールしてください。

Visual Studio 用 NuGet パッケージ マネージャー パッケージが強調表示された [拡張機能と更新プログラム] ダイアログ ボックスのスクリーンショット。

注意

Web サイトのデプロイ用に Visual Studio Azure SDK がインストールされていることを確認してください。

  1. Visual Studio または Visual Studio Express を起動します。

  2. [サーバー エクスプローラー] を選択し、Azure アカウントにサインインします。 アカウントの Web サイト リソースを作成するには、サインインする必要があります。

  3. Visual Studio の [ファイル] メニューで、[新規作成]>[プロジェクト] を選択します。

  4. 検索ボックスに「Web API」と入力します。

  5. [ASP.NET Core Web API] プロジェクト テンプレートを選択して、[次へ] を選択します。

  6. [新しいプロジェクトの構成] ダイアログで、プロジェクトに AppBackend という名前を付けて、[次へ] を選択します。

  7. [追加情報] ダイアログで、次を行います。

    • [フレームワーク][.NET 6.0 (長期的なサポート)] になっていることを確認します。
    • [コントローラーを使用する (最小限の API を使用する場合はオフにします)] チェック ボックスがオンになっていることを確認します。
    • [OpenAPI サポートを有効にする] チェック ボックスをオフにします。
    • [作成] を選択します

WeatherForecast テンプレート ファイルを削除する

  1. 新しい AppBackend プロジェクトからサンプル ファイルの WeatherForecast.csControllers/WeatherForecastController.cs を削除します。
  2. Properties\launchSettings.json を開きます。
  3. launchUrl プロパティを weatherforcast から appbackend に変更します。

[Microsoft Azure Web App の構成] ウィンドウで、サブスクリプションを選択し、 [App Service プラン] の一覧で次のいずれかの操作を実行します。

  • 作成済みの Azure App Service プランを選択します。
  • [新しい App Service プランの作成] を選択し、App Service プランを作成します。

このチュートリアルではデータベースは必要ありません。 App Service プランを選択したら、 [OK] を選択して、プロジェクトを作成します。

[Microsoft Azure Web App の構成] ウィンドウ

App Service プランを構成するためのこのページが表示されない場合、チュートリアルを続行してください。 これはアプリの発行時に後で構成できます。

WebAPI バックエンドに対してクライアントを認証する

このセクションでは、新しいバックエンドに対して AuthenticationTestHandler という名前の新しいメッセージ ハンドラー クラスを作成します。 このクラスは DelegatingHandler から派生し、メッセージ ハンドラーとして追加されるため、バックエンドに送信されるすべての要求を処理できます。

  1. ソリューション エクスプローラーで、AppBackend プロジェクトを右クリックし、 [追加][クラス] の順に選択します。

  2. 新しいクラスに「AuthenticationTestHandler.cs」という名前を付け、 [追加] を選択して、クラスを生成します。 説明を簡単にするために、このクラスでは、基本認証を使用してユーザーを認証します。 実際のアプリでは、任意の認証スキームを使用できます。

  3. AuthenticationTestHandler.cs に次の using ステートメントを追加します。

    using System.Net.Http;
    using System.Threading;
    using System.Security.Principal;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
  4. AuthenticationTestHandler.cs で、AuthenticationTestHandler クラス定義を次のコードに置き換えます。

    このハンドラーは、次の 3 つの条件を満たす場合に要求を承認します。

    • 要求に Authorization ヘッダーが含まれている。
    • 要求に 基本 認証が使用されている。
    • ユーザー名の文字列とパスワードの文字列が同じである。

    それ以外の場合、要求は拒否されます。 この認証は、認証と認可の正規のアプローチではありません。 このチュートリアルのための単なる例にすぎません。

    要求メッセージが認証され、AuthenticationTestHandler によって承認される場合、基本認証ユーザーは HttpContext の現在の要求に添付されます。 HttpContext のユーザー情報は、後で別のコントローラー (RegisterController) で使用され、通知登録の要求にタグを追加します。

    public class AuthenticationTestHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var authorizationHeader = request.Headers.GetValues("Authorization").First();
    
            if (authorizationHeader != null && authorizationHeader
                .StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
            {
                string authorizationUserAndPwdBase64 =
                    authorizationHeader.Substring("Basic ".Length);
                string authorizationUserAndPwd = Encoding.Default
                    .GetString(Convert.FromBase64String(authorizationUserAndPwdBase64));
                string user = authorizationUserAndPwd.Split(':')[0];
                string password = authorizationUserAndPwd.Split(':')[1];
    
                if (VerifyUserAndPwd(user, password))
                {
                    // Attach the new principal object to the current HttpContext object
                    HttpContext.Current.User =
                        new GenericPrincipal(new GenericIdentity(user), new string[0]);
                    System.Threading.Thread.CurrentPrincipal =
                        System.Web.HttpContext.Current.User;
                }
                else return Unauthorized();
            }
            else return Unauthorized();
    
            return base.SendAsync(request, cancellationToken);
        }
    
        private bool VerifyUserAndPwd(string user, string password)
        {
            // This is not a real authentication scheme.
            return user == password;
        }
    
        private Task<HttpResponseMessage> Unauthorized()
        {
            var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
            var tsc = new TaskCompletionSource<HttpResponseMessage>();
            tsc.SetResult(response);
            return tsc.Task;
        }
    }
    

    Note

    セキュリティに関する注意: AuthenticationTestHandler クラスは、本当の認証を提供するわけではありません。 基本認証を模倣するためだけに使用されるため、安全ではありません。 実稼働のアプリケーションとサービスでは、セキュリティで保護された認証メカニズムを実装する必要があります。

  5. メッセージ ハンドラーを登録するには、Program.cs ファイルの Register メソッドの末尾に次のコードを追加します。

    config.MessageHandlers.Add(new AuthenticationTestHandler());
    
  6. 変更を保存します。

WebAPI バックエンドを使用して通知に登録する

このセクションでは、Notification Hubs のクライアント ライブラリを使用して、通知用にユーザーとデバイスを登録する要求を処理する新しいコントローラーを WebAPI バックエンドに追加します。 コントローラーでは、AuthenticationTestHandler で認証され、HttpContext に添付されたユーザーのユーザー タグを追加します。 タグは、"username:<actual username>" という形式の文字列になります。

  1. ソリューション エクスプローラーで AppBackend プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。

  2. 左側のウィンドウにある [オンライン] を選択し、 [検索] ボックスに「Microsoft.Azure.NotificationHubs」と入力します。

  3. 結果の一覧で、 [Microsoft Azure Notification Hubs] を選択してから、 [インストール] を選択します。 インストールが完了したら、NuGet パッケージ マネージャーのウィンドウを閉じます。

    この操作によって、Microsoft.Azure.Notification Hubs NuGet パッケージを使用して Azure Notification Hubs SDK に参照が追加されます。

  4. 通知の送信に使用する通知ハブとの接続を表す新しいクラス ファイルを作成します。 ソリューション エクスプローラーで、Models フォルダーを右クリックし、 [追加][クラス] の順に選択します。 新しいクラスに「Notifications.cs」という名前を付け、 [追加] を選択して、クラスを生成します。

    [新しい項目の追加] ウィンドウ

  5. Notifications.cs で、ファイルの先頭に次の using ステートメントを追加します。

    using Microsoft.Azure.NotificationHubs;
    
  6. Notifications クラス定義を以下のコードに置き換えます。2 つのプレースホルダーは、通知ハブに対する (フル アクセス権を持つ) 接続文字列と、ハブ名 (Azure Portalで確認できます) に置き換えます。

    public class Notifications
    {
        public static Notifications Instance = new Notifications();
    
        public NotificationHubClient Hub { get; set; }
    
        private Notifications() {
            Hub = NotificationHubClient.CreateClientFromConnectionString("<your hub's DefaultFullSharedAccessSignature>",
                                                                            "<hub name>");
        }
    }
    

    重要

    先に進む前に、ハブの名前DefaultFullSharedAccessSignature を入力します。

  7. 次に、RegisterController という名前の新しいコントローラーを作成します。 ソリューション エクスプローラーで、Controllers フォルダーを右クリックし、 [追加][コントローラー] の順に選択します。

  8. [API コントローラー - 空][追加] の順に選択します。

  9. [コントローラー名] ボックスに「RegisterController」と入力して、新しいクラスに名前を付け、 [追加] を選択します。

    [コントローラーの追加] ウィンドウ。

  10. RegisterController.cs に次の using ステートメントを追加します。

    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.NotificationHubs.Messaging;
    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  11. RegisterController クラス定義内で、次のコードを追加します。 このコードでは、HttpContext に添付されるユーザーのユーザー タグを追加します。 ユーザーは認証され、追加したメッセージ フィルター AuthenticationTestHandler で HttpContext に添付されます。 また、要求されたタグを登録する権限をユーザーが持っていることを確認するコードをオプションで追加することもできます。

    private NotificationHubClient hub;
    
    public RegisterController()
    {
        hub = Notifications.Instance.Hub;
    }
    
    public class DeviceRegistration
    {
        public string Platform { get; set; }
        public string Handle { get; set; }
        public string[] Tags { get; set; }
    }
    
    // POST api/register
    // This creates a registration id
    public async Task<string> Post(string handle = null)
    {
        string newRegistrationId = null;
    
        // make sure there are no existing registrations for this push handle (used for iOS and Android)
        if (handle != null)
        {
            var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);
    
            foreach (RegistrationDescription registration in registrations)
            {
                if (newRegistrationId == null)
                {
                    newRegistrationId = registration.RegistrationId;
                }
                else
                {
                    await hub.DeleteRegistrationAsync(registration);
                }
            }
        }
    
        if (newRegistrationId == null) 
            newRegistrationId = await hub.CreateRegistrationIdAsync();
    
        return newRegistrationId;
    }
    
    // PUT api/register/5
    // This creates or updates a registration (with provided channelURI) at the specified id
    public async Task<HttpResponseMessage> Put(string id, DeviceRegistration deviceUpdate)
    {
        RegistrationDescription registration = null;
        switch (deviceUpdate.Platform)
        {
            case "mpns":
                registration = new MpnsRegistrationDescription(deviceUpdate.Handle);
                break;
            case "wns":
                registration = new WindowsRegistrationDescription(deviceUpdate.Handle);
                break;
            case "apns":
                registration = new AppleRegistrationDescription(deviceUpdate.Handle);
                break;
            case "fcm":
                registration = new FcmRegistrationDescription(deviceUpdate.Handle);
                break;
            default:
                throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
    
        registration.RegistrationId = id;
        var username = HttpContext.Current.User.Identity.Name;
    
        // add check if user is allowed to add these tags
        registration.Tags = new HashSet<string>(deviceUpdate.Tags);
        registration.Tags.Add("username:" + username);
    
        try
        {
            await hub.CreateOrUpdateRegistrationAsync(registration);
        }
        catch (MessagingException e)
        {
            ReturnGoneIfHubResponseIsGone(e);
        }
    
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    
    // DELETE api/register/5
    public async Task<HttpResponseMessage> Delete(string id)
    {
        await hub.DeleteRegistrationAsync(id);
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    
    private static void ReturnGoneIfHubResponseIsGone(MessagingException e)
    {
        var webex = e.InnerException as WebException;
        if (webex.Status == WebExceptionStatus.ProtocolError)
        {
            var response = (HttpWebResponse)webex.Response;
            if (response.StatusCode == HttpStatusCode.Gone)
                throw new HttpRequestException(HttpStatusCode.Gone.ToString());
        }
    }
    
  12. 変更を保存します。

WebAPI バックエンドから通知を送信する

このセクションでは、クライアント デバイスが通知を送信する方法を公開する新しいコントローラーを追加します。 この通知は、ASP.NET WebAPI バックエンドの Azure Notification Hubs .NET ライブラリを使用する username タグに基づいています。

  1. 前のセクションで RegisterController を作成したときと同じ方法で、NotificationsController という別の新しいコントローラーを作成します。

  2. NotificationsController.cs に次の using ステートメントを追加します。

    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  3. NotificationsController クラスに次のメソッドを追加します。

    このコードでは、プラットフォーム通知サービス (PNS) の pns パラメーターに基づく通知の種類を送信します。 to_tag の値はメッセージの ユーザー名 タグを設定するために使用します。 このタグは、アクティブな通知ハブ登録のユーザー名のタグと一致する必要があります。 通知メッセージは、POST 要求の本文からプルされ、ターゲット PNS に合わせた形式に設定されます。

    サポートされているデバイスで通知の受信に使用される PNS に応じて、各種形式で通知がサポートされています。 たとえば Windows デバイスの場合、別の PNS で直接はサポートされていない WNS によるトースト通知を使用することもできます。 このような場合、バックエンドが、通知を、サポートを計画しているデバイスの PNS でサポートされている形式に設定する必要があります。 その後、NotificationHubClient クラスで適切な送信 API を使用します。

    public async Task<HttpResponseMessage> Post(string pns, [FromBody]string message, string to_tag)
    {
        var user = HttpContext.Current.User.Identity.Name;
        string[] userTag = new string[2];
        userTag[0] = "username:" + to_tag;
        userTag[1] = "from:" + user;
    
        Microsoft.Azure.NotificationHubs.NotificationOutcome outcome = null;
        HttpStatusCode ret = HttpStatusCode.InternalServerError;
    
        switch (pns.ToLower())
        {
            case "wns":
                // Windows 8.1 / Windows Phone 8.1
                var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">" + 
                            "From " + user + ": " + message + "</text></binding></visual></toast>";
                outcome = await Notifications.Instance.Hub.SendWindowsNativeNotificationAsync(toast, userTag);
                break;
            case "apns":
                // iOS
                var alert = "{\"aps\":{\"alert\":\"" + "From " + user + ": " + message + "\"}}";
                outcome = await Notifications.Instance.Hub.SendAppleNativeNotificationAsync(alert, userTag);
                break;
            case "fcm":
                // Android
                var notif = "{ \"data\" : {\"message\":\"" + "From " + user + ": " + message + "\"}}";
                outcome = await Notifications.Instance.Hub.SendFcmNativeNotificationAsync(notif, userTag);
                break;
        }
    
        if (outcome != null)
        {
            if (!((outcome.State == Microsoft.Azure.NotificationHubs.NotificationOutcomeState.Abandoned) ||
                (outcome.State == Microsoft.Azure.NotificationHubs.NotificationOutcomeState.Unknown)))
            {
                ret = HttpStatusCode.OK;
            }
        }
    
        return Request.CreateResponse(ret);
    }
    
  4. アプリケーションを実行し、ここまでの作業に問題がないことを確認するために、F5 キーを選択します。 アプリにより、Web ブラウザーが開き、ASP.NET ホーム ページに表示されます。

新しい WebAPI バックエンドを発行する

次に、このアプリを Azure の Web サイトにデプロイして、すべてのデバイスからアクセスできるようにします。

  1. AppBackend プロジェクトを右クリックして [発行] を選択します。

  2. 発行先として [Microsoft Azure App Service] を選択し、[発行] を選択します。 [App Service の作成] ウィンドウが開きます。 このウィンドウでは、Azure で ASP.NET Web アプリを実行するために必要なすべての Azure リソースを作成できます。

    [Microsoft Azure App Service] タイル

  3. [App Service の作成] ウィンドウで、Azure アカウントを選択します。 [変更の種類]>[Web アプリ] の順に選択します。 既定の Web アプリ名をそのまま保持し、 [サブスクリプション][リソース グループ][App Service プラン] の順に選択します。

  4. [作成] を選択します

  5. [概要] セクションの [サイト URL] プロパティをメモします。 この URL は、このチュートリアルの後半で使用する "バックエンドエンドポイント" です。

  6. [発行] を選択します。

ウィザードの完了後に、Azure に ASP.NET Web アプリを発行してから、既定のブラウザーでアプリを開きます。 アプリケーションが Azure App Services に表示されます。

URL では、前に指定した Web アプリ名が http://<アプリ名>.azurewebsites.net という形式で使用されます。

UWP クライアントのコードを更新する

このセクションでは、「チュートリアル: Azure Notification Hubs を使用してユニバーサル Windows プラットフォーム アプリに通知を送信する」のチュートリアルで完成したプロジェクト内のコードを更新します。 このプロジェクトは、既に Windows ストアに関連付けられている必要があります。 また、通知ハブを使用するように構成されている必要があります。 このセクションでは、新しい WebAPI バックエンドを呼び出すコードを追加し、それを通知の登録および送信に使用します。

  1. Visual Studio で、「チュートリアル: Azure Notification Hubs を使用してユニバーサル Windows プラットフォーム アプリに通知を送信する」で作成したソリューションを開きます。

  2. ソリューション エクスプローラーで、ユニバーサル Windows プラットフォーム (UWP) プロジェクトを右クリックし、 [NuGet パッケージの管理] をクリックします。

  3. 左側で、 [参照] を選択します。

  4. [検索] ボックスに、「Http Client」と入力します。

  5. 結果の一覧で、 [System.Net.Http] をクリックし、 [インストール] をクリックします。 インストールを完了します。

  6. NuGet [検索] ボックスに戻り、「Json.net」と入力します。 Newtonsoft.json パッケージをインストールしてから、NuGet パッケージ マネージャー ウィンドウを閉じます。

  7. ソリューション エクスプローラーで、WindowsApp プロジェクトの [MainPage.xaml] をダブルクリックして、それを Visual Studio エディターで開きます。

  8. MainPage.xaml ファイルの <Grid> セクションを次のコードで置き換えます。このコードは、ユーザーを認証するためのユーザー名とパスワードのテキスト ボックスを追加します。 さらに、通知メッセージと通知を受け取るユーザー名タグのテキスト ボックスも追加します。

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
    
        <TextBlock Grid.Row="0" Text="Notify Users" HorizontalAlignment="Center" FontSize="48"/>
    
        <StackPanel Grid.Row="1" VerticalAlignment="Center">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Row="0" Grid.ColumnSpan="3" Text="Username" FontSize="24" Margin="20,0,20,0"/>
                <TextBox Name="UsernameTextBox" Grid.Row="1" Grid.ColumnSpan="3" Margin="20,0,20,0"/>
                <TextBlock Grid.Row="2" Grid.ColumnSpan="3" Text="Password" FontSize="24" Margin="20,0,20,0" />
                <PasswordBox Name="PasswordTextBox" Grid.Row="3" Grid.ColumnSpan="3" Margin="20,0,20,0"/>
    
                <Button Grid.Row="4" Grid.ColumnSpan="3" HorizontalAlignment="Center" VerticalAlignment="Center"
                            Content="1. Login and register" Click="LoginAndRegisterClick" Margin="0,0,0,20"/>
    
                <ToggleButton Name="toggleWNS" Grid.Row="5" Grid.Column="0" HorizontalAlignment="Right" Content="WNS" IsChecked="True" />
                <ToggleButton Name="toggleFCM" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Center" Content="FCM" />
                <ToggleButton Name="toggleAPNS" Grid.Row="5" Grid.Column="2" HorizontalAlignment="Left" Content="APNS" />
    
                <TextBlock Grid.Row="6" Grid.ColumnSpan="3" Text="Username Tag To Send To" FontSize="24" Margin="20,0,20,0"/>
                <TextBox Name="ToUserTagTextBox" Grid.Row="7" Grid.ColumnSpan="3" Margin="20,0,20,0" TextWrapping="Wrap" />
                <TextBlock Grid.Row="8" Grid.ColumnSpan="3" Text="Enter Notification Message" FontSize="24" Margin="20,0,20,0"/>
                <TextBox Name="NotificationMessageTextBox" Grid.Row="9" Grid.ColumnSpan="3" Margin="20,0,20,0" TextWrapping="Wrap" />
                <Button Grid.Row="10" Grid.ColumnSpan="3" HorizontalAlignment="Center" Content="2. Send push" Click="PushClick" Name="SendPushButton" />
            </Grid>
        </StackPanel>
    </Grid>
    
  9. ソリューション エクスプローラーで、 (Windows 8.1) プロジェクトと (Windows Phone 8.1) プロジェクトの MainPage.xaml.cs ファイルを開きます。 次の using ステートメントを両方のファイルの先頭に追加します。

    using System.Net.Http;
    using Windows.Storage;
    using System.Net.Http.Headers;
    using Windows.Networking.PushNotifications;
    using Windows.UI.Popups;
    using System.Threading.Tasks;
    
  10. WindowsApp プロジェクトの MainPage.xaml.cs で、MainPage クラスに次のメンバーを追加します。 <Enter Your Backend Endpoint> を、前に取得した実際のバックエンド エンドポイントに必ず置き換えてください。 たとえば、「 http://mybackend.azurewebsites.net 」のように入力します。

    private static string BACKEND_ENDPOINT = "<Enter Your Backend Endpoint>";
    
  11. 次のコードを、 (Windows 8.1) プロジェクトと (Windows Phone 8.1) プロジェクトの MainPage.xaml.cs 内の MainPage クラスに追加します。

    PushClick メソッドは、 [プッシュを送信する] ボタン用のクリック ハンドラーです。 それは、バックエンドを呼び出して、ユーザー名タグが to_tag パラメーターと一致するすべてのデバイスへの通知をトリガーします。 通知メッセージは、要求本文で JSON コンテンツとして送信されます。

    LoginAndRegisterClick メソッドは、 [ログインして登録] ボタン用のクリック ハンドラーです。 これは、基本的な認証トークン (認証スキームで使用される任意のトークンを表します) をローカル ストレージ内に格納してから、RegisterClient を使用してバックエンドを使用した通知に登録します。

    private async void PushClick(object sender, RoutedEventArgs e)
    {
        if (toggleWNS.IsChecked.Value)
        {
            await sendPush("wns", ToUserTagTextBox.Text, this.NotificationMessageTextBox.Text);
        }
        if (toggleFCM.IsChecked.Value)
        {
            await sendPush("fcm", ToUserTagTextBox.Text, this.NotificationMessageTextBox.Text);
        }
        if (toggleAPNS.IsChecked.Value)
        {
            await sendPush("apns", ToUserTagTextBox.Text, this.NotificationMessageTextBox.Text);
    
        }
    }
    
    private async Task sendPush(string pns, string userTag, string message)
    {
        var POST_URL = BACKEND_ENDPOINT + "/api/notifications?pns=" +
            pns + "&to_tag=" + userTag;
    
        using (var httpClient = new HttpClient())
        {
            var settings = ApplicationData.Current.LocalSettings.Values;
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", (string)settings["AuthenticationToken"]);
    
            try
            {
                await httpClient.PostAsync(POST_URL, new StringContent("\"" + message + "\"",
                    System.Text.Encoding.UTF8, "application/json"));
            }
            catch (Exception ex)
            {
                MessageDialog alert = new MessageDialog(ex.Message, "Failed to send " + pns + " message");
                alert.ShowAsync();
            }
        }
    }
    
    private async void LoginAndRegisterClick(object sender, RoutedEventArgs e)
    {
        SetAuthenticationTokenInLocalStorage();
    
        var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
    
        // The "username:<user name>" tag gets automatically added by the message handler in the backend.
        // The tag passed here can be whatever other tags you may want to use.
        try
        {
            // The device handle used is different depending on the device and PNS.
            // Windows devices use the channel uri as the PNS handle.
            await new RegisterClient(BACKEND_ENDPOINT).RegisterAsync(channel.Uri, new string[] { "myTag" });
    
            var dialog = new MessageDialog("Registered as: " + UsernameTextBox.Text);
            dialog.Commands.Add(new UICommand("OK"));
            await dialog.ShowAsync();
            SendPushButton.IsEnabled = true;
        }
        catch (Exception ex)
        {
            MessageDialog alert = new MessageDialog(ex.Message, "Failed to register with RegisterClient");
            alert.ShowAsync();
        }
    }
    
    private void SetAuthenticationTokenInLocalStorage()
    {
        string username = UsernameTextBox.Text;
        string password = PasswordTextBox.Password;
    
        var token = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(username + ":" + password));
        ApplicationData.Current.LocalSettings.Values["AuthenticationToken"] = token;
    }
    
  12. App.xaml.cs を開いて、OnLaunched() イベント ハンドラーから InitNotificationsAsync() の呼び出しを見つけます。 InitNotificationsAsync()への呼び出しをコメント アウトするか削除します。 ボタン ハンドラーは、通知の登録を初期化します。

    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        //InitNotificationsAsync();
    
  13. [WindowsApp] プロジェクトを右クリックし、 [追加] をクリックしてから、 [クラス] をクリックします。 クラスに RegisterClient.cs という名前を付け、 [OK] をクリックしてクラスを生成します。

    このクラスは、プッシュ通知用に登録するために、アプリ バックエンドに接続するために必要な REST 呼び出しをラップします。 「 アプリ バックエンドからの登録 」で説明しているとおり、Notification Hubs によって作成された registrationIdsもローカルに格納されます。 [ログインして登録] ボタンをクリックすると、ローカル ストレージに格納されている承認トークンが使用されます。

  14. 次の using ステートメントを、RegisterClient.cs file ファイルの先頭に追加します。

    using Windows.Storage;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using Newtonsoft.Json;
    using System.Threading.Tasks;
    using System.Linq;
    
  15. RegisterClient クラス定義内で、次のコードを追加します。

    private string POST_URL;
    
    private class DeviceRegistration
    {
        public string Platform { get; set; }
        public string Handle { get; set; }
        public string[] Tags { get; set; }
    }
    
    public RegisterClient(string backendEndpoint)
    {
        POST_URL = backendEndpoint + "/api/register";
    }
    
    public async Task RegisterAsync(string handle, IEnumerable<string> tags)
    {
        var regId = await RetrieveRegistrationIdOrRequestNewOneAsync();
    
        var deviceRegistration = new DeviceRegistration
        {
            Platform = "wns",
            Handle = handle,
            Tags = tags.ToArray<string>()
        };
    
        var statusCode = await UpdateRegistrationAsync(regId, deviceRegistration);
    
        if (statusCode == HttpStatusCode.Gone)
        {
            // regId is expired, deleting from local storage & recreating
            var settings = ApplicationData.Current.LocalSettings.Values;
            settings.Remove("__NHRegistrationId");
            regId = await RetrieveRegistrationIdOrRequestNewOneAsync();
            statusCode = await UpdateRegistrationAsync(regId, deviceRegistration);
        }
    
        if (statusCode != HttpStatusCode.Accepted && statusCode != HttpStatusCode.OK)
        {
            // log or throw
            throw new System.Net.WebException(statusCode.ToString());
        }
    }
    
    private async Task<HttpStatusCode> UpdateRegistrationAsync(string regId, DeviceRegistration deviceRegistration)
    {
        using (var httpClient = new HttpClient())
        {
            var settings = ApplicationData.Current.LocalSettings.Values;
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", (string) settings["AuthenticationToken"]);
    
            var putUri = POST_URL + "/" + regId;
    
            string json = JsonConvert.SerializeObject(deviceRegistration);
                            var response = await httpClient.PutAsync(putUri, new StringContent(json, Encoding.UTF8, "application/json"));
            return response.StatusCode;
        }
    }
    
    private async Task<string> RetrieveRegistrationIdOrRequestNewOneAsync()
    {
        var settings = ApplicationData.Current.LocalSettings.Values;
        if (!settings.ContainsKey("__NHRegistrationId"))
        {
            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", (string)settings["AuthenticationToken"]);
    
                var response = await httpClient.PostAsync(POST_URL, new StringContent(""));
                if (response.IsSuccessStatusCode)
                {
                    string regId = await response.Content.ReadAsStringAsync();
                    regId = regId.Substring(1, regId.Length - 2);
                    settings.Add("__NHRegistrationId", regId);
                }
                else
                {
                    throw new System.Net.WebException(response.StatusCode.ToString());
                }
            }
        }
        return (string)settings["__NHRegistrationId"];
    
    }
    
  16. すべての変更を保存します。

アプリケーションをテストする

  1. 両方の Windows でアプリケーションを起動します。

  2. 下の画面に示すように、 [ユーザー名][パスワード] を入力します。 Windows Phone で入力するユーザー名とパスワードとは異なるユーザー名とパスワードを入力する必要があります。

  3. [ログインして登録] をクリックし、ログインしたことを示すダイアログを確認します。 このコードにより、 [プッシュを送信する] ボタンも有効になります。

    ユーザー名とパスワードが入力された Notification Hubs アプリケーションのスクリーンショット。

  4. 次に、 [受信ユーザー タグ] フィールドに、登録されているユーザー名を入力します。 通知メッセージを入力し、 [プッシュを送信する] をクリックします。

  5. 一致するユーザー名タグが登録されているデバイスだけが通知メッセージを受信します。

    プッシュされたメッセージが表示された Notification Hubs アプリケーションのスクリーンショット。

次のステップ

このチュートリアルでは、タグが登録に関連付けられている特定のユーザーにプッシュ通知を送信する方法を学習しました。 場所に基づいたプッシュ通知を送信する方法を学習するには、次のチュートリアルに進んでください。