Abstract: In Part 5 of of their “Using Windows Azure to Build Back-End Services for Windows 8 apps” series Peter Laudati, Brian Hitney and Andrew Duthie show us how to quickly add the ability to implement push notifications for his GameLeader Service using Azure Mobile Services. Check out the full article here. Watch Part 1 | Part 2 | Part 3 | Part 4 After watching this video, follow these next steps: Step #1 – Try Windows Azure: No cost. No obligation. 90-Day FREE trial. Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Register for our Windows Azure Hands-on Lab Online (HOLO) events today! Windows Azure Hands-on Labs Online Blogs: Brian Hitney’s blog Peter Laudati’s blog Andrew Duthie’s Blog Videos: Microsoft DevRadio: How to Get Started with Windows Azure Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites? Microsoft DevRadio: (Part 2) Windows Azure Web Sites Explained Microsoft DevRadio: How to Integrate TFS Projects with Windows Azure Web Sites Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)
Abstract: In Part 4 of of their “Using Windows Azure to Build Back-End Services for Windows 8 apps” series Peter Laudati, Brian Hitney and Andrew Duthie show us how to build the same game leaderboard service on top of Windows Azure Mobile Services. Tune in as Andrew demos for us how to get started as well as lays out what some of the +/- are for using Azure Mobile Services for this kind of service. Check out the full article here. Watch Part 1 | Part 2 | Part 3 After watching this video, follow these next steps: Step #1 – Try Windows Azure: No cost. No obligation. 90-Day FREE trial. Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Register for our Windows Azure Hands-on Lab Online (HOLO) events today! Windows Azure Hands-on Labs Online Blogs: Brian Hitney’s blog Peter Laudati’s blog Andrew Duthie’s Blog Videos: Microsoft DevRadio: How to Get Started with Windows Azure Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites? Microsoft DevRadio: (Part 2) Windows Azure Web Sites Explained Microsoft DevRadio: How to Integrate TFS Projects with Windows Azure Web Sites Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)
Abstract: Back for part 3 in their series for “Using Windows Azure to Build Back-End Services for Windows 8 apps”, Peter Laudati, Brian Hitney and Andrew Duthie show us how easy it is to host services built with the ASP.NET Web API using the new Windows Azure Web Sites feature. Check out the full article here. Part 1 | Part 2 After watching this video, follow these next steps: Step #1 – Try Windows Azure: No cost. No obligation. 90-Day FREE trial. Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Register for our Windows Azure Hands-on Lab Online (HOLO) events today! Windows Azure Hands-on Labs Online Blogs: Brian Hitney’s blog Peter Laudati’s blog Andrew Duthie’s Blog Videos: Microsoft DevRadio: How to Get Started with Windows Azure Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites? Microsoft DevRadio: (Part 2) Windows Azure Web Sites Explained Microsoft DevRadio: How to Integrate TFS Projects with Windows Azure Web Sites Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)
Abstract: Peter Laudati, Brian Hitney and Andrew Duthie are back for part 2 of their series and in today’s episode Andrew shows us how to deploy the OData Service for his Windows 8 app to Windows Azure as well as outlines the advantages and disadvantages to building back-end services via this approach. After watching this video, follow these next steps: Step #1 – Try Windows Azure: No cost. No obligation. 90-Day FREE trial. Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Register for our Windows Azure Hands-on Lab Online (HOLO) events today! Windows Azure Hands-on Labs Online Blogs: Brian Hitney’s blog Peter Laudati’s blog Andrew Duthie’s Blog Videos: Microsoft DevRadio: How to Get Started with Windows Azure Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites? Microsoft DevRadio: (Part 2) Windows Azure Web Sites Explained Microsoft DevRadio: How to Integrate TFS Projects with Windows Azure Web Sites Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)
When developing locally, often times you don’t want to use SSL for a variety of reasons. There’s no real point, since the request isn’t going over the wire. Most of the time, connections are done via the loopback 127.0.0.1 address (although localhost can be used) which throws certificate errors. This one problem is often easy to solve, but it relates to a bigger issue: dictating when (and when not) to use SSL on your site. In the ol’ days, you wouldn’t want an entire site to be SSL for performance reasons. Ideally, you want to gracefully redirect users to/from SSL based on the requirements of the page. If a user navigates to a secure section like their account page, you’d like to use SSL. If they navigate away to a page not needing SSL, you’d want to use http and not https. There are a LOT of ways to do this, such as using MVC filters for MVC based applications. One way I’ve solved this before was simply calling a method like so with each request: private void SetupSslIfNeeded()
{
//bail out on local connections – never need ssl
if (Request.IsLocal)
{
return;
}
bool requiresSsl = false;
string curPath = Request.Path;
if (curPath.StartsWith("/account", StringComparison.OrdinalIgnoreCase) ||
curPath.StartsWith("/user", StringComparison.OrdinalIgnoreCase) ||
curPath.StartsWith("/admin", StringComparison.OrdinalIgnoreCase))
{
requiresSsl = true;
}
//redirect to secure page
if (requiresSsl && !Page.Request.IsSecureConnection)
{
string currentUrl = HttpContext.Current.Request.Url.ToString();
string newUrl = currentUrl.Replace("http://", "https://");
Response.Redirect(newUrl);
}
//redirect to non-secure page
if (!requiresSsl && Page.Request.IsSecureConnection)
{
string currentUrl = HttpContext.Current.Request.Url.ToString();
string newUrl = currentUrl.Replace("https://", "http://");
Response.Redirect(newUrl);
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
It’s a little more verbose than it needs to be, but it’s done to because there were a few port handling lines I left out for simplicity.
What this will do is avoid using SSL for local connections, and any page on the site except for those in the account, user, or admin folders. The main downside of this approach is that it requires a redirect, which is a round trip to the server. Ideally, you’d want your links to always be smart enough to know if they should go http:// or https://, but realistically, context switching between SSL and non-SSL pages is pretty rare so the client needing to endure the few extra milliseconds is an acceptable situation. This is the way we currently handle SSL on http://www.rockpaperazure.com.
Abstract: Peter Laudati and Brian Hitney welcome fellow Developer Evangelist, Andrew Duthie to the show as they kick off their series on how to build back-end services for their Windows 8 apps using Windows Azure. Tune in for part 1 as Andrew gives an overview of the series and introduces some potential techniques you could incorporate as you build your back-end services. After watching this video, follow these next steps: Step #1 – Try Windows Azure: No cost. No obligation. 90-Day FREE trial. Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Register for our Windows Azure Hands-on Lab Online (HOLO) events today! Windows Azure Hands-on Labs Online Blogs: Brian Hitney’s blog Peter Laudati’s blog Andrew Duthie’s Blog Videos: Microsoft DevRadio: How to Get Started with Windows Azure Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites? Microsoft DevRadio: (Part 2) Windows Azure Web Sites Explained Microsoft DevRadio: How to Integrate TFS Projects with Windows Azure Web Sites Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)
Never too late to post! Here’s an episode of DevRadio Peter and I did on TFS Projects in Azure! Abstract: Peter Laudati and Brian Hitney are back for today’s show as they show us how we can integrate TFS (Team Foundation Server) projects with Windows Azure Web Sites. They also discuss Windows Azure’s latest price reduction for Storage as well as tee up new features in Windows Azure Mobile Services. After watching this video, follow these next steps: Step #1 – Try Windows Azure: No cost. No obligation. 90-Day FREE trial. Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Register for our Windows Azure Hands-on Lab Online (HOLO) events today! Windows Azure Hands-on Labs Online Blogs: Brian Hitney’s blog Peter Laudati’s blog Videos: Microsoft DevRadio: How to Get Started with Windows Azure Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites? Microsoft DevRadio: (Part 2) Windows Azure Web Sites Explained Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)
What’s this? Another Windows Azure Mobile Services (WAMS) post?! In the next version of my app, I keep a record of the user’s Channel in order to send down notifications. The built in todo list example does this or something very similar. My table in WAMS looks like: Not shown are a couple of fields, but of particular interest is the device Id. I realized that one user might have multiple devices, so the channel then is tied to the device Id. I still haven’t found a perfect way to do this yet – right now, I’m using a random GUID on first run. In my WAMS script, if the point that is submitted is “within range” of another user, we’ll send a notification down to update the tile. I go into this part in my blog post: Best Practices on Sending Live Tiles. But what do you do if the channel is expired? This comes up a lot in testing, because the app is removed/reinstalled many times. I stumbled on this page, Push Notification Service Request and Response Headers, on MSDN. There is a lot of great info on that page. While I should have more robust solution for handling all these conditions, the one in particular I’m interested in is the Channel Expired response, highlighted below: HTTP response code Description Recommended action 200 OK The notification was accepted by WNS. None required. 400 Bad Request One or more headers were specified incorrectly or conflict with another header. Log the details of your request. Inspect your request and compare against this documentation. 401 Unauthorized The cloud service did not present a valid authentication ticket. The OAuth ticket may be invalid. Request a valid access token by authenticating your cloud service using the access token request. 403 Forbidden The cloud service is not authorized to send a notification to this URI even though they are authenticated. The access token provided in the request does not match the credentials of the app that requested the channel URI. Ensure that your package name in your app's manifest matches the cloud service credentials given to your app in the Dashboard. 404 Not Found The channel URI is not valid or is not recognized by WNS. Log the details of your request. Do not send further notifications to this channel; notifications to this address will fail. 405 Method Not Allowed Invalid method (GET, DELETE, CREATE); only POST is allowed. Log the details of your request. Switch to using HTTP POST. 406 Not Acceptable The cloud service exceeded its throttle limit. Log the details of your request. Reduce the rate at which you are sending notifications. 410 Gone The channel expired. Log the details of your request. Do not send further notifications to this channel. Have your app request a new channel URI. 413 Request Entity Too Large The notification payload exceeds the 5000 byte size limit. Log the details of your request. Inspect the payload to ensure it is within the size limitations. 500 Internal Server Error An internal failure caused notification delivery to fail. Log the details of your request. Report this issue through the developer forums. 503 Service Unavailable The server is currently unavailable. Log the details of your request. Report this issue through the developer forums. Obviously getting a new channel URI is ideal, but the app has to do that on the client (and will) next time the user runs the app. In the mean time, I want to delete this channel because it’s useless. In my script which sends the notifications, we’ll examine the result on the callback and either delete the channel if expired, or, if success, send a badge update because that’s needed, too. (Future todo task: try to combine Live Tile and badges in one update.) push.wns.send(channelUri, payload, 'wns/tile',
{
client_id: 'ms-app://<my app id>',
client_secret: 'my client secret',
headers: { 'X-WNS-Tag' : 'SomeTag' }
},
function (error, result) {
if (error)
{
//if the channel has expired, delete from channel table
if (error.statusCode == 410){
removeExpiredChannel(channelUri)
}
}
else
{
//notification sent
updateBadge(channelUri);
}
}
);
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Removing expired channels can be done with something like:
function removeExpiredChannel(channelUri)
{
var sql = "delete from myapp.Channel where ChannelUri = ?";
var params = [channelUri];
mssql.query(sql, params,
{
success: function(results) {
console.log('Removed Expired Channel: ' + channelUri)
}
});
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
On my todo list is to add more robust support for different response codes – for example, in addition to a 410 response, a 404 would also want to delete the channel record in the table.
First, many thanks to Chris Risner for the assistance on this solution! Chris is part of the corp DPE team and has does an extensive amount of work with Windows Azure Mobile Services (WAMS) – including this session at //build, which was a great resource for getting started. If you go through the demo of getting started with WAMS building a TodoList, the idea is that the data in the todo list is locked down to each user. One of the nice things about WAMS is that it’s easy to enforce this via server side javascript … for example, to ensure only the current user’s rows are returned, the following read script can be used that enforces the rows returned only belong to the current user: function read(query, user, request) {
query.where({ userId: user.userId });
request.execute();
}
If we crack open the database, we’ll see that the userId is an identifier, like the below for a Microsoft Account:
MicrosoftAccount:0123456789abcd
When the app connects to WAMS, the data returned includes the userId … for example, if we look at the JSON in fiddler:
The app never displays this information, and it is requested over SSL, but it’s an important consideration and here’s why. What if we have semi-public data? In the next version of Dark Skies, I allow users to pin favorite spots on the map. The user has the option to make those points public or keep them private … for example, maybe they pin a great location for stargazing and want to share it with the world:
… Or, maybe the user pins their home locations or a private farm they have permission to use, where it might be inappropriate to show publically.
Now here comes the issue: if a location is shared publically, that userId is included in the JSON results. Let’s say I launch the app and see 10 public pins. If I view the JSON in fiddler, I’ll see the userId for each one of those public pins – for example:
Now, the userId contains no personally identifiable information. Is this a big deal, then? It’s not like it is the user’s name or address, and it would only be included in spots the user is sharing publically anyway.
But, if a hacker ever finds a way to map a userId back to a specific person, this is a security issue. Even my app doesn’t know who the users really are, it just knows the identifier. Still, I think from a best practice/threat modeling perspective, if we can scrub that data, we should. Note: this issue doesn’t exist with the todo list example, because the user only, and ever, sees their own data.
Ideally, what we’d like to do is return the userId if it’s the current user’s userId. If the point belongs to another user, we should scrub that from the result set. To do this via a read script in WAMS, we could do something like:
function read(query, user, request) {
request.execute( {
success: function(results) {
//scrub user token
if (results.length > 0)
{
for (var i=0; i< results.length; i++)
{
if (results[i].UserId != user.userId)
{
results[i].UserId = 'scrubbeduser';
}
}
}
request.respond();
}
});
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }If we look at the results in fiddler, we’ll see that I’ll get my userId for any of my points, but the userId is scrubbed if it’s another user’s points that are shared publically:
[Note: these locations are random spots on the map for testing.]
Doing this is a good practice. The database of course has the correct info, but the data for public points is guaranteed to be anonymous should a vulnerability ever present itself. The downside of this approach is the extra overhead as we’re iterating the results – but, this is fairly minor given the relatively small amounts of data.
Technical point: In my database and classes, I use Pascal case (as a matter of preference), as you can see in the above fiddler captures, such as UserId. In the todo example and in the javascript variables, objects are conventionally camel case. So, if you’re using any code here, just be aware that case does matter in situations like this:
if (results[i].UserId != user.userId) // watch casing!
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Be sure they match your convention. Since Pascal case is the standard for properties in C#, and camel case is the standard in javascript, properties in .NET can be decorated with the datamember attribute to make them consistent in both locations – something I, just as a matter of preference, prefer not to do:
[DataMember(Name = "userId")]
public string UserId { get; set; }
I was surprised, yet delighted, that Windows Azure Mobile Services uses a SQL database. Schema-less table storage has its place and is the right solution at times, but for most data driven applications, I’d argue otherwise. In my last post, I wrote about sending notifications by writing the payload explicitly from a Windows Azure Mobile Service. In short, this allows us to include multiple tiles in the payload, accommodating users of both wide and square tiles. In my application, I want to execute a query to find push notification channels that match some criteria. If we look at the Windows Azure Mobile Services script reference, the mssql object allows us to query the database using T-SQL and parameters, such as: mssql.query('select top 1 * from statusupdates', {
success: function(results) {
console.log(results);
}
});
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }In my case, the query is a bit more complicated. I want to join another table and use a function to do some geospatial calculations – while I could do this with inline SQL like in the above example, it’s not very maintainable or testable. Fortunately, calling a stored procedure is quite easy.
Consider the following example: every time the user logs in, the Channel URI is updated. What I’d like to do is find out how many new locations (called PointsOfInterest) have been modified since the last time the user has logged in. To do that, I have a stored procedure like so:
create procedure [darkskies].[NewLocationsForChannel]
(
@channelUri as nvarchar(512) = null
)
as
select c.ChannelUri, count(1) as NumNewLocations
from darkskies.Channel c
inner join darkskies.PointOfInterest p
on c.UserId = p.UserId
where p.LastUpdated > c.LastUpdated
and c.ChannelUri = @channelUri
group by c.ChannelUri
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Writing something like that inline to the mssql object would be painful. As a stored procedure, it’s much easier to test and encapsulate. In my WAMS script, I’ll call that procedure and send down a badge update:
function updateBadge(channelUri)
{
var params = [channelUri];
var sql = "exec darkskies.NewLocationsForChannel ?";
mssql.query(sql, params,
{
success: function(results) {
if (results.length > 0) {
for (var i=0; i< results.length; i++)
{
if (results[i].ChannelUri !== null &&
results[i].ChannelUri.length > 0)
{
push.wns.sendBadge(results[i].ChannelUri,
results[i].NumNewLocations);
}
}
}
}
});
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }This section of code only updates the badge of the Windows 8 Live Tile, but it works out nicely with tile queuing:
Note: this app is live in the Windows 8 Store, however, at the time of this writing, these features have not yet been released. In the next few posts, we’ll look at the notifications a bit more, including how to pull off some geospatial stuff in WAMS.