/WP7.1/Templates/C#/WPCloud.Mem/WindowsPhoneCloud.Web/Controllers/PushNotificationsController.cs
C# | 334 lines | 258 code | 51 blank | 25 comment | 17 complexity | 51ec4f94c5cc3043f3806b2ffad03f8a MD5 | raw file
- // ----------------------------------------------------------------------------------
- // Microsoft Developer & Platform Evangelism
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
- // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
- // OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
- // ----------------------------------------------------------------------------------
- // The example companies, organizations, products, domain names,
- // e-mail addresses, logos, people, places, and events depicted
- // herein are fictitious. No association with any real company,
- // organization, product, domain name, email address, logo, person,
- // places, or events is intended or should be inferred.
- // ----------------------------------------------------------------------------------
-
- namespace Microsoft.Samples.WindowsPhoneCloud.Web.Controllers
- {
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Net.Security;
- using System.Net.Sockets;
- using System.Security.Authentication;
- using System.Security.Cryptography.X509Certificates;
- using System.Text;
- using System.Web.Mvc;
- using Microsoft.Samples.WindowsPhoneCloud.Web.Infrastructure;
- using Microsoft.Samples.WindowsPhoneCloud.Web.Models;
- using Microsoft.Samples.WindowsPhoneCloud.Web.UserAccountWrappers;
- using Microsoft.WindowsAzure;
- using Microsoft.WindowsAzure.StorageClient;
- using WindowsPhone.Recipes.Push.Messages;
-
- [CustomAuthorize(Roles = PrivilegeConstants.AdminPrivilege)]
- public class PushNotificationsController : Controller
- {
- private const int DefaultPort = 2195;
-
- private readonly CloudQueueClient cloudQueueClient;
- private readonly IPushUserEndpointsRepository pushUserEndpointsRepository;
-
- #if ACS
- private readonly IUserRepository userRepository;
-
- public PushNotificationsController()
- : this(null, new UserTablesServiceContext(), new UserTablesServiceContext())
- {
- }
-
- [CLSCompliant(false)]
- public PushNotificationsController(CloudQueueClient cloudQueueClient, IPushUserEndpointsRepository pushUserEndpointsRepository, IUserRepository userRepository)
- {
- if (GetStorageAccountFromConfigurationSetting() == null)
- {
- if (cloudQueueClient == null)
- {
- throw new ArgumentNullException("cloudQueueClient", "Cloud Queue Client cannot be null if no configuration is loaded.");
- }
- }
-
- this.cloudQueueClient = cloudQueueClient ?? GetStorageAccountFromConfigurationSetting().CreateCloudQueueClient();
- this.userRepository = userRepository;
- this.pushUserEndpointsRepository = pushUserEndpointsRepository;
- }
-
- public ActionResult Microsoft()
- {
- var users = this.pushUserEndpointsRepository
- .GetAllPushUsers()
- .Select(userId => new UserModel { UserId = userId, UserName = this.userRepository.GetUser(userId).Name });
-
- return this.View(users);
- }
- #else
- private readonly IMembershipService membershipService;
-
- public PushNotificationsController()
- : this(null, new UserTablesServiceContext(), new AccountMembershipService())
- {
- }
-
- [CLSCompliant(false)]
- public PushNotificationsController(CloudQueueClient cloudQueueClient, IPushUserEndpointsRepository pushUserEndpointsRepository, IMembershipService membershipService)
- {
- if (GetStorageAccountFromConfigurationSetting() == null)
- {
- if (cloudQueueClient == null)
- {
- throw new ArgumentNullException("cloudQueueClient", "Cloud Queue Client cannot be null if no configuration is loaded.");
- }
- }
-
- this.cloudQueueClient = cloudQueueClient ?? GetStorageAccountFromConfigurationSetting().CreateCloudQueueClient();
- this.membershipService = membershipService;
- this.pushUserEndpointsRepository = pushUserEndpointsRepository;
- }
-
- public ActionResult Microsoft()
- {
- var users = this.pushUserEndpointsRepository
- .GetAllPushUsers()
- .Select(userId => new UserModel { UserId = userId, UserName = this.membershipService.GetUserByProviderUserKey(new Guid(userId)).UserName });
-
- return this.View(users);
- }
- #endif
-
- public ActionResult Apple()
- {
- return this.View();
- }
-
- [HttpPost]
- public ActionResult SendMicrosoftToast(string userId, string message)
- {
- if (string.IsNullOrWhiteSpace(message))
- {
- return this.Json("The notification message cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet);
- }
-
- var resultList = new List<MessageSendResultLight>();
- var uris = this.pushUserEndpointsRepository.GetPushUsersByName(userId).Select(u => u.ChannelUri);
-
- var pushUserEndpoint = this.pushUserEndpointsRepository.GetPushUsersByName(userId).FirstOrDefault();
-
- var toast = new ToastPushNotificationMessage
- {
- SendPriority = MessageSendPriority.High,
- Title = message
- };
-
- foreach (var uri in uris)
- {
- var messageResult = toast.SendAndHandleErrors(new Uri(uri));
- resultList.Add(messageResult);
- if (messageResult.Status.Equals(MessageSendResultLight.Success))
- {
- this.QueueMessage(pushUserEndpoint, message);
- }
- }
-
- return this.Json(resultList, JsonRequestBehavior.AllowGet);
- }
-
- [HttpPost]
- public ActionResult SendMicrosoftTile(string userId, string message)
- {
- if (string.IsNullOrWhiteSpace(message))
- {
- return this.Json("The notification message cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet);
- }
-
- var resultList = new List<MessageSendResultLight>();
- var pushUserEndpointList = this.pushUserEndpointsRepository.GetPushUsersByName(userId);
- foreach (var pushUserEndpoint in pushUserEndpointList)
- {
- var tile = new TilePushNotificationMessage
- {
- SendPriority = MessageSendPriority.High,
- Count = ++pushUserEndpoint.TileCount
- };
-
- var messageResult = tile.SendAndHandleErrors(new Uri(pushUserEndpoint.ChannelUri));
- resultList.Add(messageResult);
- if (messageResult.Status.Equals(MessageSendResultLight.Success))
- {
- this.QueueMessage(pushUserEndpoint, message);
-
- this.pushUserEndpointsRepository.UpdatePushUserEndpoint(pushUserEndpoint);
- }
- }
-
- return this.Json(resultList, JsonRequestBehavior.AllowGet);
- }
-
- [HttpPost]
- public ActionResult SendMicrosoftRaw(string userId, string message)
- {
- if (string.IsNullOrWhiteSpace(message))
- {
- return this.Json("The notification message cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet);
- }
-
- var resultList = new List<MessageSendResultLight>();
- var uris = this.pushUserEndpointsRepository.GetPushUsersByName(userId).Select(u => u.ChannelUri);
- var raw = new RawPushNotificationMessage
- {
- SendPriority = MessageSendPriority.High,
- RawData = Encoding.UTF8.GetBytes(message)
- };
-
- foreach (var uri in uris)
- {
- resultList.Add(raw.SendAndHandleErrors(new Uri(uri)));
- }
-
- return this.Json(resultList, JsonRequestBehavior.AllowGet);
- }
-
- [HttpPost]
- public ActionResult SendAppleMessage(string deviceId, string message)
- {
- if (string.IsNullOrWhiteSpace(deviceId))
- {
- return this.Json("The deviceId cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet);
- }
-
- if (string.IsNullOrWhiteSpace(message))
- {
- return this.Json("The notification message cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet);
- }
-
- // Get the Apple Notification Service settings.
- var thumprint = ConfigReader.GetConfigValue("AppleNotificationService.Thumbprint");
- var host = ConfigReader.GetConfigValue("AppleNotificationService.Host");
- var port = 0;
- if (!int.TryParse(ConfigReader.GetConfigValue("AppleNotificationService.Port"), NumberStyles.Integer, CultureInfo.InvariantCulture, out port))
- {
- port = DefaultPort;
- }
-
- X509Certificate2Collection certCollection = null;
- try
- {
- // Load the Apple Notification Service certificate from the store.
- var clientCert = CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, thumprint);
- certCollection = new X509Certificate2Collection(clientCert);
- }
- catch (Exception exception)
- {
- var errorMessage = string.Format(CultureInfo.InvariantCulture, "Error getting the X509 certificate from the store: {0}", exception.Message);
- return this.Json(errorMessage, JsonRequestBehavior.AllowGet);
- }
-
- TcpClient client = null;
- try
- {
- // Open connection and connect.
- client = new TcpClient(host, port);
- var sslStream = new SslStream(client.GetStream(), false);
-
- sslStream.AuthenticateAsClient(host, certCollection, SslProtocols.Tls, false);
-
- byte[] array = null;
- using (var memoryStream = new MemoryStream())
- {
- var writer = new BinaryWriter(memoryStream);
-
- // Construct the message.
- writer.Write((byte)0); // Command
- writer.Write((byte)0); // First byte of device ID length
- writer.Write((byte)32); // Device id length
-
- // Convert to hex and write to message.
- byte[] deviceToken = new byte[deviceId.Length / 2];
- for (int i = 0; i < deviceToken.Length; i++)
- {
- deviceToken[i] = byte.Parse(deviceId.Substring(i * 2, 2), NumberStyles.HexNumber);
- }
-
- writer.Write(deviceToken);
-
- // Construct payload within JSON message framework.
- var payload = string.Format(CultureInfo.InvariantCulture, "{{\"aps\":{{\"alert\":\"{0}\",\"badge\":1}}}}", message);
-
- // Write payload data.
- writer.Write((byte)0); // First byte of payload length
- writer.Write((byte)payload.Length); // Actual payload length
- byte[] b1 = Encoding.UTF8.GetBytes(payload);
- writer.Write(b1);
- writer.Flush();
-
- array = memoryStream.ToArray();
- }
-
- // Send across the wire.
- sslStream.Write(array);
- sslStream.Flush();
- }
- catch (AuthenticationException exception)
- {
- var errorMessage = string.Format(CultureInfo.InvariantCulture, "Error authenticating against APN: {0}", exception.Message);
- return this.Json(errorMessage, JsonRequestBehavior.AllowGet);
- }
- catch (Exception exception)
- {
- var errorMessage = string.Format(CultureInfo.InvariantCulture, "There was an error sending the notification message: {0}", exception.Message);
- return this.Json(errorMessage, JsonRequestBehavior.AllowGet);
- }
- finally
- {
- // Close the client connection.
- client.Close();
- }
-
- // Success.
- return this.Json("Success", JsonRequestBehavior.AllowGet);
- }
-
- private static CloudStorageAccount GetStorageAccountFromConfigurationSetting()
- {
- CloudStorageAccount account = null;
- try
- {
- account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
- }
- catch (InvalidOperationException)
- {
- account = null;
- }
-
- return account;
- }
-
- private static string GetQueueName(string applicationId, string deviceId, string userId)
- {
- var uniqueName = string.Concat(applicationId, deviceId, userId);
-
- return string.Concat("notification", uniqueName.GetHashCode());
- }
-
- private void QueueMessage(PushUserEndpoint pushUser, string message)
- {
- var queueName = GetQueueName(pushUser.PartitionKey, pushUser.RowKey, pushUser.UserId);
- var queue = this.cloudQueueClient.GetQueueReference(queueName);
-
- queue.CreateIfNotExist();
- queue.AddMessage(new CloudQueueMessage(message));
- }
- }
- }