Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια

C# and .NET Tips and Tricks

Quests in programming in .NET

Ιούνιος 2012 - Δημοσιεύσεις

Push Notifications in Windows 8 with ASP.NET MVC

In the previous post we have seen how we create scheduled and periodic tile notifications with Javascript for metro applications.

In this post we will cover push notifications. Push notifications do not require from your app to tell the OS that it has to query a service at specific time intervals as periodic notifications do. They rely on the fact that an external service can actually change the tile when it sees fit (hence the “push” name).

Such notifications cover scenarios like having an application that monitors stock prices and the user specifying that he wants to be informed when the price of a stock falls under a specific value. The push notification will change the tile’s appearance when the premise is fulfilled. Note that a periodic notification would not suit in this case unless the user could accept a possible maximum half hour delay of the delivery of the notification.

Push notifications work as follows:

 

  1. Your metro app requests from the device a specific URI which uniquely defines the combination app/device.
  2. Your metro app then transmits this URI to the server application you have implemented (in our case you will see that this is a ASP.NET MVC project). Your metro app can also transmit any other information specific to the logic of the notification required from the user.
  3. Your server application receives and saves the URI and it also receives and saves the logic for the push notification (when and under what circumstances the metro app desires to be notified).
  4. In order for your server application to send the push notification to that URI, it has to tell the Windows Push Notification Service (WNS-simply a server application offered for free from Microsoft) and this service will contact the actual device based on the supplied URI with the desired notification. So prior to doing so, your server application needs to authenticate itself with that service.

 

Before doing anything else you need to register your app. Full instructions can be found here and differentiate on whether you are a registered developer for the store or you just want to play around to see how things work. We will choose the second approach and therefore the short version of the registration instructions (in the document of the link above this is located in the Remarks section). So proceed as follows::

 

  1. Navigate to this link.
  2. Follow the instructions by supplying the application’s name and the publisher as required and click next.
  3. You will get a bunch of items that you will need to put in your application’s manifest file. This has connected the WNS with your application so they both know that each other exists via the keys. This has also given you all the appropriate stuff for your server application to use in order to communicate with the app on a user’s device (in a sense the URI will supply the exact machine/app and the security keys you obtained are an extra safety).

 

You can now start developing your server application. Create a new ASP.NET MVC project, create a ServicesController and provide a Register action as follows:

   1: public JsonResult Register(string uri)
   2: {
   3:     string[] parms = HttpContext.Request.RawUrl.Split(new string[] { "uri=" }, 
                                                    StringSplitOptions.RemoveEmptyEntries);
   4:     Subscribers.Uris.Add(parms[1]);
   5:     return Json(new { Success = true, Uri = uri }, JsonRequestBehavior.AllowGet);
   6: }

Note here that although we receive as a parameter the uri of the subscriber we prefer it to get it from the query string of the raw URL. This is because ASP.NET MVC decodes the encoded URL. The problem is that the uri you receive is partially encoded (the link is not encoded while the parameters are) and therefore it is not possible to get it in its decoded version adn  encode it again. Take good care of that cause otherwise you will be getting a 404 not found error when you try to send the notification and you will not be able to know the source of the error.

The Subscribers list is the one that will hold the URIs to be notified (metro apps). For our demo the class resides in the Models folder and is as follows:

   1: public static class Subscribers
   2: {
   3:     public static List<string> Uris = new List<string>();
   4: }

Of course in reality you would persist this information along with the notification predicates in a DB or file storage since the static list can be wiped out at any time! For our demo though we are just fine with this.

Having done that, if we deploy this simple ASP.NET MVC project and we provide in the metro app the following lines of code:

   1: Windows.Networking.PushNotifications.PushNotificationChannelManager
   2:     WinJS.xhr({ url: "http://server.application.address/Register?uri=" + channel.uri })
   3:         if (xhr.status < 200 || xhr.status >= 300) {
   4:             var dialog = new Windows.UI.Popups
   5:             dialog.showAsync();
   6:         }
   7:     });
   8: });
   9:  

We basically create a URI and then pass it to the server application (we can encrypt it for security but in this demo for simplicity we leave it as is).

So, we have managed to notify our server application that the metro app exists, with the URI it got from the Windows 8 device and is ready to receive Push Notifications. Of course, we have not supplied any predicates on when we require to receive such notifications (the logic and encoding of the way this will be communicated to the server app is up to the developer but will probably reside in some encoded string in a query string parameter (ie parameters) specified after the uri parameter: http://addres?uri=…&parameters=… This will be decoded by the server app along with the URI. In our case we will be generating the notification whenever we want from the server application.

Now all we have to do is write the code that will send the tile notification. This code can reside in any kind of application (windows service, WPF app) but in our case we will just provide an action in the ServicesController that exposes a view with an input box and a button. When the user clicks on the button, the text of the input box is sent as a tile notification to all subscriber URIs. The action in high level is as follows:

   1: WNSAuthorizer.OAuthToken Token = WNSAuthorizer.GetOAuthToken(<clientsecret>,<packageSID>);
   2: foreach (var uri in Subscribers.Uris)
   3: {
   4:     PushNotifier Notifier = new PushNotifier(uri, Token.AccessToken);
   5:     Notifier.SendNotification(PushNotifier.PushType.Tile, msg, "");
   6: }

Where in <clientsecret> and <packageSID> you provide the credentials you got from registering the application for push notifications. The code above uses a helper class to get authorization with the WNS (WNSAuthorizer) and then uses a helper class (PushNotifier) to send the push notification to all recipients. The correct format of the tile notification can be seen if you download the code for the helper classes at the end of this post. Note that this code is based on the code given in the article. Basically the notification for the tile has identical xml payload with the one presented in the previous post for periodic and scheduled notifications. Also the code allows you to send different kinds of push notifications tile and badge.

 

And this is it! You have managed to build an ASP.NET MVC application that will be able to send push notifications to windows 8 metro style apps. The ASP.NET MVC project can be downloaded

(for obvious reasons the credentials have been removed from the project and therefore you need to supply the ones that apply to your app. The project is in VS2012 but you can open the files in VS2010 and see the logic).
Tile Notifications in Windows 8 (Javascript)

This post will cover the main aspects of using Tile Notifications in a Metro-Style application. The only topic that will not be covered is “Push Notifications” since those deserve a post on their own and will follow in the near future.

So what are “Tile Notifications”? Well as you already know, each Metro-Style application has its own tile which appears in the start screen. This tile is either a “square” or a “wide” one as depicted in the following figure:

 

tiles

 

The user gets to choose from the “start menu” application bar which one of the two will be shown. You specify in your application that you support both by providing in the package.appxmanifest file (Application UI tab) a image for both the Logo and the Wide logo property:

 

LogoWide

 

It is important that you provide the wide version of the logo cause otherwise your application will not be able to appear as “wide” in the start menu and that option will not exist for the user in the application bar. Having done this, you may use the tile to make it “alive”, that is to provide some meaningful information (related to your app) to the user. The way this information will be delivered, defines the type of the notification:

 

Scheduled: Your application, when it is executed, schedules for some tile notification in the future. A possible scenario for this is when you have for example a calendar app, the user adds an appointment and defines that he would like to get notified. Then your app may schedule a notification to appear in the tile when the time comes.

Periodic: Your applications, at specific time intervals, asks from the operating system to make a request to a web service and display in the application’s tile the content it receives from the service. A possible scenario for this is when for example your app displays news of some kind and you want your tile to always present the latest news.

Push: Those are notifications that are initiated from a web service outside of your app which instructs the OS to change your tile with the content the service provides. As stated before this kind of notification and the way to create a web server capable of delivering such notification will be explained in a future post.

 

Apart from the type of notifications you may also define a notifications queue. That is you can define whether a newer notification will overwrite the current one displayed on the tile or the new notification will be inserted in a queue of the five most recent ones to be cycled on the tile. So let’s get started with the following code that schedules for a notification after 10 seconds:

   1: var notifications = Windows.UI.Notifications;
   2: var currentDate = new Date();

The following lines create the tile appearance for its “wide” version. The version is defined by the template (highlighted in yellow). The list of available templates may be found here. Basically the content provided for the tile is nothing more than a simple xml document with the information required for each tile type.

   1: var tileXMLWide = notifications.TileUpdateManager.getTemplateContent
                                               (notifications.TileTemplateType.tileWideText03);
   2: var tileAttributesWide = tileXMLWide.getElementsByTagName("text"); 
   3: tileAttributesWide[0].appendChild(tileXMLWide.createTextNode("First Notification"));

The following lines create the tile appearance for its “square” version (of course we may only create one of the two but it is good practice if we support both versions to support both versions in the notifications also):

   1: var tileXMLSquare = notifications.TileUpdateManager.getTemplateContent
                                               (notifications.TileTemplateType.tileSquareText01);
   2: var tileAttributesSquare = tileXMLSquare.getElementsByTagName("text"); 
   3: tileAttributesSquare[0].appendChild(tileXMLSquare.createTextNode("1st"));

Finally the two versions “square” and “wide” are packed in a single XML document:

   1: var node = tileXMLWide.importNode(tileXMLSquare.getElementsByTagName("binding")[0], true); 
   2: tileXMLWide.getElementsByTagName("visual").item(0).appendChild(node);

And the tile update is ready to be scheduled

   1: var futureTile = new notifications.ScheduledTileNotification(tileXMLWide, 
                                                       new Date(new Date().getTime() + 10 * 1000));
   2: futureTile.id = "Tile1"; 
   3: notifications.TileUpdateManager.createTileUpdaterForApplication().addToSchedule(futureTile);

If we want to add more scheduled notifications we just create them as above and add them to the Schedule with the previous (last) line. Now because we have not specified any "”queue” the next notification will overwrite the current. Therefore the tile’s id, tag does not play an role. If we don’t provide a new notification the current one will remain visible for ever unless we provide an expiration date for the notification. Adding the following line to the notification we have created before adding it to the schedule will make the notification disappear after 10secs from its appearance:

   1: futureTile.expirationTime = new Date(new Date().getTime() + 20 * 1000);

Now for periodic notifications we need to create a basic service (web service) that returns the XML required for updating the tile. The XML to generate is the same as before and taken from the possible templates here. Again we main combine the two tile versions square and wide to support both. An example of possible XML generated from the service is given in this link. So how can you create first of all such a service? One way to go is to use an ASP.NET MVC project. Go ahead and create one. Then erase the Content, Script etc folders. Create a class in the Models folder as follows:

   1: public class TileData
   2: {
   3:     public string Image1 { get; set; }
   4:     public string Image2 { get; set; }
   5:     public string Image3 { get; set; }
   6:     public string Image4 { get; set; }
   7:     public string Image5 { get; set; }
   8:  
   9:     public List<string> Text { get; set; }
  10: }

Then write the following code in the HomeController’s Index action (you basically need to populate with data the model you have created in the Models folder and pass it to the view). In the following example we just populate the model with random values:

   1: public ActionResult Index()
   2: {
   3:     TileData Model = new TileData();
   4:     // Popullate the model with your data here
   5:     return View(Model);
   6: }

Finally your view (for the index action) will be something like the following:

   1: @{
   2:     Layout = null;
   3:     Response.ContentType = "text/xml";
   4: }
   5: @model MetroStylePullNotificationDemo.Models.TileData 
   6: <tile>
   7:     <visual lang="en-US">
   8:         <binding template="TileSquarePeekImageAndText03">
   9:             <image id="1" src="@Model.Image1" />
  10:             @for (int i=0;i<Model.Text.Count;i++)
  11:             {
  12:                 @:<text id="@(i+1)">@Model.TextIdea</text>
  13:             }
  14:         </binding>
  15:         <binding template="TileWideImageCollection">
  16:             <image id="1" src="@Model.Image1" />
  17:             <image id="2" src="@Model.Image2" />
  18:             <image id="3" src="@Model.Image3" />
  19:             <image id="4" src="@Model.Image4" />
  20:             <image id="5" src="@Model.Image5" />
  21:         </binding>
  22:     </visual>
  23: </tile>

You then deploy your service and you are “good to go” server-side. In your metro-style app it is very easy to tell the OS that you need it to query that service to update your tile with the following code:

   1: var recurrence = notifications.PeriodicUpdateRecurrence.halfHour; 
   2: var url = new Windows.Foundation.Uri("http://www.progware.org/windows8/tiles/"); 
   3: notifications.TileUpdateManager.createTileUpdaterForApplication().
                                      startPeriodicUpdate(url, recurrence);

Note that the period is an enumeration and can be of specific values only (30min, 1hour, 6hour, 12hour,24hour) and that is expected since the OS will handle the requests and your app lives in an ecosystem with hundreds of other apps that will compete for the same resources and bandwidth.

 

No matter the notification type (scheduled or periodic) you can activated the queue for holding the last ones and recycling them in a random order that favors the most recent ones. This is done with a single directive:

   1: notifications.TileUpdateManager.createTileUpdaterForApplication().enableNotificationQueue(true);

Having the queue means that your notification may live more than you want them to or you may need to update an already present notification in the queue. For this reason in this case it is important to tag your notifications by setting their tag property (for scheduled notifications). In periodic notifications this tag is inserted at the response header (see here– the Remarks section). Actually, in the header, we also store the notification’s expiration time.

So this was a brief overview on using tile notifications in metro-style apps with Javascript.We have seen scheduled and periodic notifications. I n the near future there will be a post for push notifications.

Posted: Τετάρτη, 27 Ιουνίου 2012 8:51 πμ από iwannis | 0 σχόλια
Δημοσίευση στην κατηγορία: ,