Created
November 8, 2012 07:04
-
-
Save jimoneil/4037330 to your computer and use it in GitHub Desktop.
Sample code for OAuth and push notification handling for Windows Store applications
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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