Step 2: Configure push notifications in a provider-hosted apps for SharePoint

apps for SharePoint

Learn how to create push notifications for a provider-hosted apps for SharePoint using remote event receivers.

Last modified: June 24, 2014

Applies to: SharePoint

In this article
Prerequisites for configuring push notifications
Create push notifications in a provider-hosted app for SharePoint using a remote event receiver
Next steps
Additional resources

This is the second article in a three-part series that shows how to create a companion mobile app for SharePoint. For more information, see How to: Create a companion mobile app for an app for SharePoint.

In this step, you will add a remote event receiver to an app for SharePoint (created in Step 1: Create a list-based provider-hosted app in SharePoint 2013) to send push notifications to the mobile app. Using the Microsoft Push Notification Service (MPNS), Windows Phone apps can receive notifications through the events triggered on apps for SharePoint. The phone app doesn't have to poll the server for changes to, for example, the items in a list on which the phone app is based. The app can be registered to receive notifications from the server, and an event receiver can initiate a notification and send it to the receiving app for handling. The push notification is relayed to Windows Phone devices by MPNS.

Apps for SharePoint can be SharePoint-hosted, or provider-hosted apps. Each of these has different ways of handling events depending on their hosting. Provider-hosted apps handle events using remote event receivers, and SharePoint-hosted apps handle events using event handlers, as in traditional server-side solutions. Because you’re working on a provider-hosted app in this procedure, you will create a remote event receiver to handle events in the app.

Push notifications are sent to mobile apps, which are registered to receive notifications. Push notifications are triggered by an action that occurs on a specified SharePoint object. If you have a SharePoint-hosted app, you can create an event receiver to send push notifications. For more information, see http://msdn.microsoft.com/en-us/library/office/jj163784.aspx#BKMK_ServerSideSolution.

To complete this procedure, you will need the following:

  • A local installation of Microsoft Visual Studio 2012.

  • A local installation of Office Developer Tools for Visual Studio 2012.

  • A local installation of Web Deploy 2.0, which you can download from Web Deploy 2.0.

  • A local installation of SharePoint 2013. In addition, the installation must be configured to use OAuth if you want to run an event receiver, for example, to test and debug it.

    Note Note

    SharePoint 2013 is already configured to use OAuth if you’re testing the app on a target website that was created from the Developer Site definition. (You can create such a website in SharePoint 2013 Central Administration.)

Core concepts to know for push notifications

Before you start these procedures, you should have a basic understanding of what apps for SharePoint are and how provider-hosted or SharePoint-hosted apps differ. You should also understand the fundamental concepts of how to handle events in apps for SharePoint. The topics in Table 1 should give you that understanding.

Table 1. Core concepts for handling events in apps for SharePoint

Article title

Description

Overview of apps for SharePoint

Learn how you can use the new app model in SharePoint 2013 to create apps, which are small, easy-to-use solutions for end users.

Important aspects of the app for SharePoint architecture and development landscape

Learn about the model for apps for SharePoint and aspects of its architecture, including the app hosting options, the user interface options, the deployment system, the security system, and the life cycle.

Choose patterns for developing and hosting your app for SharePoint

Learn more details about the different ways that you can host apps for SharePoint.

Handling events in apps for SharePoint

Learn about the different types of events that you can handle in an app for SharePoint and how to implement them.

This section contains two steps. First, you add a .cs file to the app for SharePoint project created in Step 1: Create a list-based provider-hosted app in SharePoint 2013. Second, you add a remote event receiver to the Visual Studio 2012 project to your app solution. For more information, see How to: Create an event receiver for an app for SharePoint.

To create the classes for managing push notifications

  1. In Solution Explorer, choose the node that represents the project (named SupportCenterWeb if you follow the naming convention used in these procedures). This is the project that you created in Step 1: Create a list-based provider-hosted app in SharePoint 2013.

  2. On the Project menu, choose Add Class. The Add New Item dialog box appears with the C# Class template already selected.

  3. Specify PushNotification.cs as the name of the file, and choose Add. The class file is added to the solution and opened for editing.

  4. Replace the contents of the file with the following code.

    namespace SupportCenterWeb
    {
        class PushNotification
        {
            public PushNotificationResponse PushToast(PushNotificationSubscriber subscriber, string toastTitle, string toastMessage, string toastParam, ToastIntervalValuesEnum intervalValue)
            {
                // Construct toast notification message from parameter values.
                string toastNotification = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<wp:Notification xmlns:wp=\"WPNotification\">" +
                   "<wp:Toast>" +
                        "<wp:Text1>" + toastTitle + "</wp:Text1>" +
                        "<wp:Text2>" + toastMessage + "</wp:Text2>" +
                        "<wp:Param>" + toastParam + "</wp:Param>" +
                   "</wp:Toast> " +
                "</wp:Notification>";
    
                return SendPushNotification(NotificationTypeEnum.Toast, subscriber, toastNotification, (int)intervalValue);
            }
    
            public PushNotificationResponse PushRaw(PushNotificationSubscriber subscriber, string rawMessage, RawIntervalValuesEnum intervalValue)
            {
                return SendPushNotification(NotificationTypeEnum.Raw, subscriber, rawMessage, (int)intervalValue);
            }
    
            private PushNotificationResponse SendPushNotification(NotificationTypeEnum notificationType, PushNotificationSubscriber subscriber, string message, int intervalValue)
            {
                // Create HTTP Web Request object.
                string subscriptionUri = subscriber.ServiceToken;
                HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);
    
                // MPNS expects a byte array, so convert message accordingly.
                byte[] notificationMessage = Encoding.Default.GetBytes(message);
                
                // Set the notification request properties.
                sendNotificationRequest.Method = WebRequestMethods.Http.Post;
                sendNotificationRequest.ContentLength = notificationMessage.Length;
                sendNotificationRequest.ContentType = "text/xml";
                sendNotificationRequest.Headers.Add("X-MessageID", Guid.NewGuid().ToString());
    
                switch (notificationType)
                {
                    case NotificationTypeEnum.Tile:
                        sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "token");
                        break;
                    case NotificationTypeEnum.Toast:
                        sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
                        break;
                    case NotificationTypeEnum.Raw:
                        // A value for the X-WindowsPhone-Target header is not specified for raw notifications.
                        break;
                }            
    
                sendNotificationRequest.Headers.Add("X-NotificationClass", intervalValue.ToString());
    
                // Merge byte array payload with headers.
                using (Stream requestStream = sendNotificationRequest.GetRequestStream())
                {
                    requestStream.Write(notificationMessage, 0, notificationMessage.Length);
                }
    
                string statCode = string.Empty;
                PushNotificationResponse notificationResponse;
    
                try
                {
                    // Send the notification and get the response.
                    HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
                    statCode = Enum.GetName(typeof(HttpStatusCode), response.StatusCode);
    
                    // Create PushNotificationResponse object.
                    notificationResponse = new PushNotificationResponse((int)intervalValue, subscriber.ServiceToken);
                    notificationResponse.StatusCode = statCode;
                    foreach (string header in WP7Constants.WP_RESPONSE_HEADERS)
                    {
                        notificationResponse.Properties[header] = response.Headers[header];
                    }                
                }
                catch (Exception ex)
                {
                    statCode = ex.Message;
                    notificationResponse = new PushNotificationResponse((int)intervalValue, subscriber.ServiceToken);
                    notificationResponse.StatusCode = statCode;
                }
    
                return notificationResponse;
            }
        }
    
        internal static class WP7Constants
        {
            internal static readonly string[] WP_RESPONSE_HEADERS = 
                {
                    "X-MessageID",
                    "X-DeviceConnectionStatus",
                    "X-SubscriptionStatus",
                    "X-NotificationStatus"
                };
        }
    
        public enum TileIntervalValuesEnum
        {
            ImmediateTile = 1,
            Delay450SecondsTile = 11,
            Delay900SecondsTile = 21,
        }
    
        public enum ToastIntervalValuesEnum
        {
            ImmediateToast = 2,
            Delay450SecondsToast = 12,
            Delay900SecondsToast = 22,
        }
    
        public enum RawIntervalValuesEnum
        {
            ImmediateRaw = 3,
            Delay450SecondsRaw = 13,
            Delay900SecondsRaw = 23
        }
    
        public enum NotificationTypeEnum
        {
            Tile = 1,
            Toast = 2,
            Raw = 3
        }
    
        /// <summary>
        /// Object used for returning notification request results.
        /// </summary>
        class PushNotificationResponse
        {
            private DateTime timestamp;
            private int notificationIntervalValue;
            private string statusCode = string.Empty;
            private string serviceToken;
            private Dictionary<string, string> properties;
    
            public PushNotificationResponse(int numericalIntervalValue, string srvcToken)
            {
                timestamp = DateTime.UtcNow;
                notificationIntervalValue = numericalIntervalValue;
                serviceToken = srvcToken;
                properties = new Dictionary<string, string>();
            }
    
            public DateTime TimeStamp
            {
                get { return timestamp; }
            }
    
            public int NotificationIntervalValue
            {
                get { return notificationIntervalValue; }
            }
    
            public string StatusCode
            {
                get { return statusCode; }
                set { statusCode = value; }
            }
    
            public string ServiceToken
            {
                get { return serviceToken; }
            }
    
            public Dictionary<string, string> Properties
            {
                get { return properties; }
            }
        }
    }
    
  5. Save the file.

In this code, the PushToast and PushRaw methods take parameter arguments appropriate for the given type of notification to send, process those arguments, and then call the SendPushNotification method, which does the work of sending the notification using the Microsoft Push Notification Service. (In this sample code, a method for sending tile notifications has not been implemented.) The PushNotificationResponse class is a mechanism for encapsulating the result received from the notification request. Here, the class adds some information to the object (cast as an HttpWebResponse object) returned by the GetResponse method of the HttpWebRequest object. The event receiver you create in the following procedure uses this PushNotificationResponse class to update a notifications results list on the server.

In this section, you extend an app for SharePoint by adding a remote event receiver and enabling it to handle events that occur to list items in the app. Now create a remote event receiver class that will be triggered when an item is added to the list in your app. By doing this, you will send push notifications to devices that have been registered to receive them. (You will bind this event receiver to the Job list that is created in the app for SharePoint in Step 1: Create a list-based provider-hosted app in SharePoint 2013.)

To add a remote event receiver for push notifications

  1. In Visual Studio, open Solution Explorer, and then choose the app project's node.

  2. On the menu bar, choose Project, Add New Item.

  3. In the Installed Templates pane, choose the Office/ SharePoint node.

  4. In the Templates pane, choose the Remote Event Receiver template.

  5. In the Name box, leave the default name (SupportCenterRER), and then choose the Add button.

  6. In the What type of event receiver do you want? list, choose List Item Events.

  7. In the What item should be the event source? list, choose Cases list (SupportCenter \Cases).

  8. In the Handle the following events list, choose An item is being added, and then choose the Finish button.

    A web service is added to the web application to handle the remote event that you specified. A remote event receiver is added to the app for SharePoint and references the web service and the two list item events in the receiver’s Elements.xml file.

  9. To add functionality to the remote event receiver, add the following code in the code file for the service of the remote event receiver (that is, SupportCenterRER.svc.cs).

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.SharePoint.Client;
    using Microsoft.SharePoint.Client.EventReceivers;
    
    namespace SupportCenterWeb
    {
        public class SupportCenterRER : IRemoteEventService
        {
            public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
            {
                SPRemoteEventResult result = new SPRemoteEventResult();
    
                using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
                {
                    if (clientContext != null)
                    {
                        //Custom Code
                    }
                }
    
                return result;
            }
    
            public void ProcessOneWayEvent(SPRemoteEventProperties properties)
            {
                using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
                {
                    if (clientContext != null)
                    {
                        
    
                        //Send Push Notification to relevant subscribers
                        Web web = clientContext.Web;
    
                        PushNotificationSubscriberCollection pushSubscribers = web.PushNotificationSubscribers;
                        PushNotification pushNotification = new PushNotification();
                        int itemID = properties.ItemEventProperties.ListItemId;
                        string listTitle = properties.ItemEventProperties.ListTitle;
                        ListItem listItem = web.Lists.GetByTitle(listTitle).GetItemById(itemID);
    
                        clientContext.Load(listItem);
                        clientContext.Load(pushSubscribers);
                        clientContext.ExecuteQuery();
    
                        if (listItem["AssignedTo"] == null)
                            return;
                        // multi user field
                        string assignedUser = (listItem["AssignedTo"] as FieldUserValue[])[0].LookupValue;                    
    
                        PushNotificationResponse pushResponse = null;
    
                        foreach (PushNotificationSubscriber ps in pushSubscribers)
                        {
                            // add filter logic here for sending notification to specific user
                            string notificationTitle = string.Empty;
    
                            if (properties.EventType == SPRemoteEventType.ItemAdded)
                                notificationTitle = "New case assigned: ";
                            else if (properties.EventType == SPRemoteEventType.ItemUpdated)
                                notificationTitle = "A case assigned to you has been updated: ";
                            else
                                notificationTitle = "A case assigned to you has been removed: ";
    
            // Send a toast notification to be displayed on subscribed phones on which the app is not running.
                            pushResponse = pushNotification.PushToast(ps, notificationTitle, listItem["Title"].ToString(), string.Empty, ToastIntervalValuesEnum.ImmediateToast);
                            UpdateNotificationResultsList(clientContext, web, assignedUser, pushResponse);
    
    // Also send a raw notification to be displayed on subscribed phones on which the app is running when the item is added.
                            pushResponse = pushNotification.PushRaw(ps, notificationTitle + listItem["Title"].ToString(), RawIntervalValuesEnum.ImmediateRaw);
                            UpdateNotificationResultsList(clientContext, web, assignedUser, pushResponse);
                        }
                    }
                }
            }
    
            private void UpdateNotificationResultsList(ClientContext context, Web web, string subscriberName, PushNotificationResponse pushResponse)
            {
                List notificationsList = web.Lists.GetByTitle("Notifications");
                context.Load(notificationsList);
                context.ExecuteQuery();
    
                if (notificationsList == null)
                    return;
    
                try
                {
                    ListItem resultItem = notificationsList.AddItem(new ListItemCreationInformation());
                    resultItem["Title"] = subscriberName;
                    resultItem["NotificationTime"] = pushResponse.TimeStamp;
                    resultItem["StatusCode"] = pushResponse.StatusCode;
                    resultItem["ServiceToken"] = pushResponse.ServiceToken;
    
                    StringBuilder builder = new StringBuilder();
                    foreach (string key in pushResponse.Properties.Keys)
                    {
                        builder.AppendFormat("{0}: {1}; ", key, pushResponse.Properties[key]);
                    }
                    resultItem["Headers"] = builder.ToString();
    
                    resultItem["IntervalValue"] = pushResponse.NotificationIntervalValue;
                    resultItem.Update();
                    context.ExecuteQuery();
                }
                catch
                {
                    // Could log here if adding list item fails.
                }
            }
        }
    }
    
    
  10. Save the file.

  11. Change the Site Url property of the app for SharePoint project to the URL of the local system.

    You can develop remote event receivers and app event receivers only on local systems. After you deploy those receivers, they can be used on remote systems.

  12. Now you can deploy your app to the SharePoint site. For more information, see Deploying and installing apps for SharePoint: methods and options.

In this code, after an item is added to the list to which the event receiver is bound, push notifications are sent to subscribers that have registered to receive notifications.

The toast notification is displayed on subscribed phones (if the phone app for which the notification is intended is not running), and the message displayed is truncated if it is longer than approximately 41 characters. Raw notifications in MPNS are limited to 1024 bytes (1 kilobyte). (The exact number of characters that can be sent depends on the kind of encoding used, such as UTF-8.) Tile notifications are also subject to size limitations. Large amounts of data can't be sent using any of the notification types. The best use of these notifications is not as a mechanism for transferring data, but as a way to send short messages to subscribed phones so that certain actions can be taken on the phone. Those actions, such as refreshing a list on the phone with data from the server, may involve larger amounts of data, depending on the design of the Windows Phone app.

In the next step, Step 3: Create a mobile app and register for push notifications, you learn how to create a companion mobile app for the SharePoint app.

Show:
© 2014 Microsoft