Skip to content

Instantly share code, notes, and snippets.

@jimoneil
Created November 8, 2012 07:04
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jimoneil/4037330 to your computer and use it in GitHub Desktop.
Save jimoneil/4037330 to your computer and use it in GitHub Desktop.
Sample code for OAuth and push notification handling for Windows Store applications
/*
Copyright (c) Microsoft
All rights reserved.
Licensed under the Microsoft Limited Public License (the “License”); you may not
use this file except in compliance with the License.
You may obtain a copy of the License at http://msdn.microsoft.com/en-us/cc300389.
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS
OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
win
See the Microsoft Limited Public License (Ms-LPL) for specific language governing
permissions and limitations under the License.
*/
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Utilities
{
public static class WNSHelper
{
static String _token = null;
private static async Task RefreshTokenAsync()
{
// set the required name/value pair for the POST
var parms = new List<KeyValuePair<String,String>>();
parms.Add(new KeyValuePair<String, String>("grant_type", "client_credentials"));
parms.Add(new KeyValuePair<String, String>("scope", "notify.windows.com"));
parms.Add(new KeyValuePair<String, String>("client_id", ConfigurationManager.AppSettings["WNSPackageId"]));
parms.Add(new KeyValuePair<String, String>("client_secret", ConfigurationManager.AppSettings["WNSSecret"]));
// POST OAuth token request
var client = new HttpClient();
HttpResponseMessage response = await client.PostAsync(
"https://login.live.com/accesstoken.srf",
new FormUrlEncodedContent(parms));
// throw if there's a problem
response.EnsureSuccessStatusCode();
// get response (JSON)
String jsonContent = await response.Content.ReadAsStringAsync();
var tokenResponse =
JsonConvert.DeserializeObject<TokenPayload>(jsonContent);
// set the token
_token = tokenResponse.access_token;
}
public static async Task<NotificationResult> PushNotificationAsync(String uri, String template)
{
// make sure there's a token
if (_token == null) await RefreshTokenAsync();
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", _token));
client.DefaultRequestHeaders.Add("X-WNS-Type", "wns/toast");
client.DefaultRequestHeaders.Add("X-WNS-RequestForStatus", "true");
HttpResponseMessage response = await client.PostAsync(uri, SetContent(template));
var notificationResult = new NotificationResult(response);
if (notificationResult.RequiresTokenRefresh())
{
await RefreshTokenAsync();
response = await client.PostAsync(uri, WNSHelper.SetContent(template));
notificationResult = new NotificationResult(response);
}
return notificationResult;
}
private static StringContent SetContent(String template)
{
var requestContent = new StringContent(template);
requestContent.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
requestContent.Headers.ContentLength = template.Length;
return requestContent;
}
// OAuth response (see http://tools.ietf.org/html/draft-ietf-oauth-v2-23)
private class TokenPayload
{
public String token_type;
public String access_token;
public String expires_in;
}
}
public class NotificationResult
{
public HttpStatusCode HttpCode { get; private set; }
public String ErrorDescription { get; private set; }
public String NotificationStatus { get; private set; }
public String DeviceStatus { get; private set; }
public String DebugTrace { get; private set; }
public String MessageId { get; private set; }
public NotificationResult(HttpResponseMessage m)
{
HttpCode = m.StatusCode;
NotificationStatus = ParseHeaderValue(m.Headers, "X-WNS-NOTIFICATIONSTATUS");
ErrorDescription = ParseHeaderValue(m.Headers, "X-WNS-ERROR-DESCRIPTION");
DeviceStatus = ParseHeaderValue(m.Headers, "X-WNS-DEVICECONNECTIONSTATUS");
DebugTrace = ParseHeaderValue(m.Headers, "X-WNS-DEBUGTRACE");
MessageId = ParseHeaderValue(m.Headers, "X-WNS-MSG-ID");
}
public Boolean RequiresTokenRefresh()
{
return this.HttpCode == HttpStatusCode.Unauthorized;
}
public Boolean RequiresChannelUpdate()
{
return (this.HttpCode == HttpStatusCode.NotFound) ||
(this.HttpCode == HttpStatusCode.Gone);
}
public Boolean WasSuccessful()
{
return (this.HttpCode == HttpStatusCode.OK);
}
public override string ToString()
{
return String.Format("Notification Result: {1}{0}Message Id: {2}{0}Notification Status: {3}{0}Device Status: {4}{0}{5}",
Environment.NewLine + " ",
HttpCode, MessageId, NotificationStatus, DeviceStatus,
(ErrorDescription != String.Empty) ? String.Format("Error Description: {0}", ErrorDescription) : String.Empty);
}
private String ParseHeaderValue(HttpResponseHeaders headers, String name)
{
var headerValue = headers.Where(h => h.Key.Equals(name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault().Value;
return (headerValue == null) ? String.Empty : headerValue.FirstOrDefault();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment