Skip to content

Latest commit

 

History

History
359 lines (290 loc) · 18 KB

notification-hubs-aspnet-backend-windows-dotnet-wns-notification.md

File metadata and controls

359 lines (290 loc) · 18 KB
title description author manager services ms.service ms.tgt_pltfrm ms.devlang ms.topic ms.custom ms.date ms.author ms.reviewer ms.lastreviewed
Send notifications to specific users using Azure Notification Hubs | Microsoft Docs
Learn how to send notifications to specific users using Universal Windows Platform (UWP) applications.
sethmanheim
femila
notification-hubs
notification-hubs
mobile-windows
csharp
tutorial
mvc, devx-track-dotnet
08/17/2020
sethm
thsomasu
03/22/2019

Tutorial: Send notifications to specific users by using Azure Notification Hubs

[!INCLUDE notification-hubs-selector-aspnet-backend-notify-users]

Overview

This tutorial describes how to use Azure Notification Hubs to send push notifications to a specific app user on a specific device. An ASP.NET WebAPI backend is used to authenticate clients. When the backend authenticates a client application user, it automatically adds a tag to the notification registration. The backend uses this tag to send notifications to the specific user.

Note

The completed code for this tutorial can be found on GitHub.

In this tutorial, you take the following steps:

[!div class="checklist"]

  • Create the WebAPI project
  • Authenticate clients to the WebAPI backend
  • Register for notifications by using the WebAPI backend
  • Send notifications from the WebAPI backend
  • Publish the new WebAPI backend
  • Update the code for the client project
  • Test the application

Prerequisites

This tutorial builds on the notification hub and Visual Studio project that you created in the Tutorial: Send notifications to Universal Windows Platform apps by using Azure Notification Hubs tutorial. Therefore, complete it before starting on this tutorial.

Note

If you are using Mobile Apps in Azure App Service as your backend service, see the Mobile Apps version of this tutorial.

[!INCLUDE notification-hubs-aspnet-backend-notifyusers]

Update the code for the UWP client

In this section, you update the code in the project you completed for the Tutorial: Send notifications to Universal Windows Platform apps by using Azure Notification Hubs tutorial. The project should already be associated with the Windows store. It also should be configured to use your notification hub. In this section, you add code to call the new WebAPI backend and use it for registering and sending notifications.

  1. In Visual Studio, open the solution you created for the Tutorial: Send notifications to Universal Windows Platform apps by using Azure Notification Hubs.

  2. In Solution Explorer, right-click the Universal Windows Platform (UWP) project and then click Manage NuGet Packages.

  3. On the left-hand side, select Browse.

  4. In the Search box, type Http Client.

  5. In the results list, click System.Net.Http, and click Install. Complete the installation.

  6. Back in the NuGet Search box, type Json.net. Install the Newtonsoft.json package, and then close the NuGet Package Manager window.

  7. In Solution Explorer, in the WindowsApp project, double-click MainPage.xaml to open it in the Visual Studio editor.

  8. In the MainPage.xaml file, replace the <Grid> section with the following code: This code adds a username and password textbox that the user authenticates with. It also adds text boxes for the notification message and the username tag that should receive the notification:

    <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. In Solution Explorer, open the MainPage.xaml.cs file for the (Windows 8.1) and (Windows Phone 8.1) projects. Add the following using statements at the top of both files:

    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. In MainPage.xaml.cs for the WindowsApp project, add the following member to the MainPage class. Be sure to replace <Enter Your Backend Endpoint> with your actual backend endpoint obtained previously. For example, http://mybackend.azurewebsites.net.

    private static string BACKEND_ENDPOINT = "<Enter Your Backend Endpoint>";
  11. Add the code below to the MainPage class in MainPage.xaml.cs for the (Windows 8.1) and (Windows Phone 8.1) projects.

    The PushClick method is the click handler for the Send Push button. It calls the backend to trigger a notification to all devices with a username tag that matches the to_tag parameter. The notification message is sent as JSON content in the request body.

    The LoginAndRegisterClick method is the click handler for the Login and register button. It stores the basic authentication token (represents any token your authentication scheme uses) in local storage, then uses RegisterClient to register for notifications using the backend.

    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. Open App.xaml.cs and find the call to InitNotificationsAsync() in the OnLaunched() event handler. Comment out or delete the call to InitNotificationsAsync(). The button handler initializes notification registrations:

    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        //InitNotificationsAsync();
  13. Right-click the WindowsApp project, click Add, and then click Class. Name the class RegisterClient.cs, then click OK to generate the class.

    This class wraps the REST calls required to contact the app backend, in order to register for push notifications. It also locally stores the registrationIds created by the Notification Hub as detailed in Registering from your app backend. It uses an authorization token stored in local storage when you click the Login and register button.

  14. Add the following using statements at the top of the 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. Add the following code inside the RegisterClient class definition:

    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. Save all your changes.

Test the Application

  1. Launch the application on both Windows.

  2. Enter a Username and Password as shown in the screen below. It should differ from the user name and password you enter on Windows Phone.

  3. Click Log in and register and verify a dialog shows that you have logged in. This code also enables the Send Push button.

    Screenshot of the Notification Hubs application showing the username and password filled in.

  4. Then in the Recipient Username Tag field, enter the user name registered. Enter a notification message and click Send Push.

  5. Only the devices that have registered with the matching username tag receive the notification message.

    Screenshot of the Notification Hubs application showing the message that was pushed.

Next steps

In this tutorial, you learned how to push notifications to specific users that have tags associated with their registrations. To learn how to push location-based notifications, advance to the following tutorial:

[!div class="nextstepaction"] Push location-based notifications