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 |
[!INCLUDE notification-hubs-selector-aspnet-backend-notify-users]
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
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]
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.
-
In Visual Studio, open the solution you created for the Tutorial: Send notifications to Universal Windows Platform apps by using Azure Notification Hubs.
-
In Solution Explorer, right-click the Universal Windows Platform (UWP) project and then click Manage NuGet Packages.
-
On the left-hand side, select Browse.
-
In the Search box, type Http Client.
-
In the results list, click System.Net.Http, and click Install. Complete the installation.
-
Back in the NuGet Search box, type Json.net. Install the Newtonsoft.json package, and then close the NuGet Package Manager window.
-
In Solution Explorer, in the WindowsApp project, double-click MainPage.xaml to open it in the Visual Studio editor.
-
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>
-
In Solution Explorer, open the
MainPage.xaml.cs
file for the (Windows 8.1) and (Windows Phone 8.1) projects. Add the followingusing
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;
-
In
MainPage.xaml.cs
for the WindowsApp project, add the following member to theMainPage
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>";
-
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 theto_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 usesRegisterClient
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; }
-
Open
App.xaml.cs
and find the call toInitNotificationsAsync()
in theOnLaunched()
event handler. Comment out or delete the call toInitNotificationsAsync()
. The button handler initializes notification registrations:protected override void OnLaunched(LaunchActivatedEventArgs e) { //InitNotificationsAsync();
-
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.
-
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;
-
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"]; }
-
Save all your changes.
-
Launch the application on both Windows.
-
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.
-
Click Log in and register and verify a dialog shows that you have logged in. This code also enables the Send Push button.
-
Then in the Recipient Username Tag field, enter the user name registered. Enter a notification message and click Send Push.
-
Only the devices that have registered with the matching username tag receive the notification message.
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