Creating Windows Store Apps with Windows Azure Notification Hubs

Service Bus Notification Hubs are Service Bus entities that allow a user to send push notifications through third-party platforms, e.g. Windows Notification System (WNS), Apple Push Notification Service (APNs). Note: Support for Windows Phone’s Microsoft Push Notification Service (MPNS), and Google Cloud Messaging (GCM), targeting the Android platform, will be added soon. Every notification hub contains the credentials that are required to connect to these systems and push notifications to a specific app. Currently in Preview. Notification Hubs provide an extremely scalable, cross-platform, push notification infrastructure that enables you to efficiently route push notification messages to millions of mobile users and devices. Read ScottGu’s blog post for more detail.

You can create a Windows Store app and use a Notification Hub to send messages to the app. Follow the steps below. Fore more detail, read the instructions here.

  • Creating a simple Windows Store App
  • Create and Configure a Service Bus Notification Hub
  • Connect the App
  • Create a simple backend .NET application to send notifications

I created a sample app and was able to test the feature successfully. For your convenience, I included the sample code below. You will need to change the texts highlighted in yellow color.

Windows Store App

using Win8HubDemo.Common;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

using Microsoft.WindowsAzure.Messaging;
using System.Threading.Tasks;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;

// The Grid App template is documented at https://go.microsoft.com/fwlink/?LinkId=234226

namespace Win8HubDemo
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    sealed partial class App : Application
    {
        NotificationHub notificationHub;

        /// <summary>
        /// Initializes the singleton Application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;

            var cn = ConnectionString.CreateUsingSharedAccessSecretWithListenAccess("sb://zxhub-ns.servicebus.windows.net/","y{HXM{DD_I)0z4DI");
            notificationHub = new NotificationHub("zxhub", cn);

            this.InitializeComponent();
            this.Suspending += OnSuspending;

        }

        async Task InitializeNotificationsAsync()
        {
            await notificationHub.RefreshRegistrationsAsync();

            if (!await notificationHub.RegistrationExistsForApplicationAsync(
                                                             "myToastRegistration"))
            {
                await notificationHub.CreateTemplateRegistrationForApplicationAsync(
                    BuildTextToastTemplate(), "myToastRegistration");
            }
        }

        XmlDocument BuildTextToastTemplate()
        {
            var template =
                ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
            var textNode = template.SelectSingleNode("//text[@id='1']") as XmlElement;
            if (textNode != null)
            {
                textNode.InnerText = "$(msg)";
            }
            return template;
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>
        protected override async void OnLaunched(LaunchActivatedEventArgs args)
        {
            await InitializeNotificationsAsync();

            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active

            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();
                //Associate the frame with a SuspensionManager key                               
                SuspensionManager.RegisterFrame(rootFrame, "AppFrame");

                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    // Restore the saved session state only when appropriate
                    try
                    {
                        await SuspensionManager.RestoreAsync();
                    }
                    catch (SuspensionManagerException)
                    {
                        //Something went wrong restoring state.
                        //Assume there is no state and continue
                    }
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }
            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                if (!rootFrame.Navigate(typeof(GroupedItemsPage), "AllGroups"))
                {
                    throw new Exception("Failed to create initial page");
                }
            }
            // Ensure the current window is active
            Window.Current.Activate();

 

        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private async void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            await SuspensionManager.SaveAsync();
            deferral.Complete();
        }

        //protected async override void OnActivated(IActivatedEventArgs args)
        //{
        //    base.OnActivated(args);
        //    await InitializeNotificationsAsync();
        //}
    }
}

Backend App (Console app to simulate the process)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ServiceBus.Notifications;
using Microsoft.ServiceBus;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var cn = ServiceBusConnectionStringBuilder.CreateUsingSharedAccessSecretWithFullAccess("zxhub-ns", "C>EDC11(j?drMn$T");
            var hubClient = NotificationHubClient.CreateClientFromConnectionString(cn, "zxhub1");
            hubClient.SendTemplateNotification(new Dictionary<string, string>
                                            {
                                                {"msg", args.Length > 0 ? args[0] : "Hello"}
                                            });

        }
    }
}