PageRenderTime 58ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/WP7.1/Templates/C#/WPCloud.Mem/WindowsPhoneCloud.Web/Services/SamplePushUserRegistrationService.cs

#
C# | 307 lines | 242 code | 41 blank | 24 comment | 40 complexity | bdc1397029d22d80e13d86b171cb4754 MD5 | raw file
  1. // ----------------------------------------------------------------------------------
  2. // Microsoft Developer & Platform Evangelism
  3. //
  4. // Copyright (c) Microsoft Corporation. All rights reserved.
  5. //
  6. // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  7. // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
  8. // OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  9. // ----------------------------------------------------------------------------------
  10. // The example companies, organizations, products, domain names,
  11. // e-mail addresses, logos, people, places, and events depicted
  12. // herein are fictitious. No association with any real company,
  13. // organization, product, domain name, email address, logo, person,
  14. // places, or events is intended or should be inferred.
  15. // ----------------------------------------------------------------------------------
  16. namespace Microsoft.Samples.WindowsPhoneCloud.Web.Services
  17. {
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Globalization;
  21. using System.Linq;
  22. using System.Net;
  23. using System.ServiceModel;
  24. using System.ServiceModel.Activation;
  25. using System.ServiceModel.Web;
  26. using System.Web;
  27. using System.Web.Security;
  28. using Microsoft.Samples.WindowsPhoneCloud.Web.Infrastructure;
  29. using Microsoft.Samples.WindowsPhoneCloud.Web.Models;
  30. using Microsoft.Samples.WindowsPhoneCloud.Web.UserAccountWrappers;
  31. using Microsoft.WindowsAzure;
  32. using Microsoft.WindowsAzure.StorageClient;
  33. using WindowsPhone.Recipes.Push.Messages;
  34. [ServiceBehavior(IncludeExceptionDetailInFaults = false)]
  35. [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
  36. public class SamplePushUserRegistrationService : ISamplePushUserRegistrationService
  37. {
  38. private readonly HttpContextBase context;
  39. private readonly IPushUserEndpointsRepository pushUserEndpointsRepository;
  40. private readonly CloudQueueClient cloudQueueClient;
  41. private readonly WebOperationContext webOperationContext;
  42. #if ACS
  43. public SamplePushUserRegistrationService()
  44. : this(new HttpContextWrapper(HttpContext.Current), WebOperationContext.Current, new UserTablesServiceContext(), null)
  45. {
  46. }
  47. [CLSCompliant(false)]
  48. public SamplePushUserRegistrationService(HttpContextBase context, WebOperationContext webOperationContext, IPushUserEndpointsRepository pushUserEndpointsRepository, CloudQueueClient cloudQueueClient)
  49. {
  50. if ((context == null) && (HttpContext.Current == null))
  51. {
  52. throw new ArgumentNullException("context", "Context cannot be null if not running on a Web context.");
  53. }
  54. if (pushUserEndpointsRepository == null)
  55. {
  56. throw new ArgumentNullException("pushUserEndpointsRepository", "PushUserEndpoints repository cannot be null.");
  57. }
  58. if ((cloudQueueClient == null) && (GetStorageAccountFromConfigurationSetting() == null))
  59. {
  60. throw new ArgumentNullException("cloudQueueClient", "Cloud Queue Client cannot be null if no configuration is loaded.");
  61. }
  62. this.cloudQueueClient = cloudQueueClient ?? GetStorageAccountFromConfigurationSetting().CreateCloudQueueClient();
  63. this.webOperationContext = webOperationContext;
  64. this.context = context;
  65. this.pushUserEndpointsRepository = pushUserEndpointsRepository;
  66. }
  67. private string UserId
  68. {
  69. get
  70. {
  71. var identity = HttpContext.Current.User.Identity as Microsoft.IdentityModel.Claims.IClaimsIdentity;
  72. return identity.Claims.Single(c => c.ClaimType == Microsoft.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value;
  73. }
  74. }
  75. #else
  76. private readonly IFormsAuthentication formsAuth;
  77. private readonly IMembershipService membershipService;
  78. public SamplePushUserRegistrationService()
  79. : this(new HttpContextWrapper(HttpContext.Current), WebOperationContext.Current, new FormsAuthenticationService(), new AccountMembershipService(), new UserTablesServiceContext(), null)
  80. {
  81. }
  82. [CLSCompliant(false)]
  83. public SamplePushUserRegistrationService(HttpContextBase context, WebOperationContext webOperationContext, IFormsAuthentication formsAuth, IMembershipService membershipService, IPushUserEndpointsRepository pushUserEndpointsRepository, CloudQueueClient cloudQueueClient)
  84. {
  85. if ((context == null) && (HttpContext.Current == null))
  86. {
  87. throw new ArgumentNullException("context", "Context cannot be null if not running on a Web context.");
  88. }
  89. if (pushUserEndpointsRepository == null)
  90. {
  91. throw new ArgumentNullException("pushUserEndpointsRepository", "PushUserEndpoints repository cannot be null.");
  92. }
  93. if (formsAuth == null)
  94. {
  95. throw new ArgumentNullException("formsAuth", "Forms Authentication service cannot be null.");
  96. }
  97. if (membershipService == null)
  98. {
  99. throw new ArgumentNullException("membershipService", "Membership service cannot be null.");
  100. }
  101. if ((cloudQueueClient == null) && (GetStorageAccountFromConfigurationSetting() == null))
  102. {
  103. throw new ArgumentNullException("cloudQueueClient", "Cloud Queue Client cannot be null if no configuration is loaded.");
  104. }
  105. this.cloudQueueClient = cloudQueueClient ?? GetStorageAccountFromConfigurationSetting().CreateCloudQueueClient();
  106. this.webOperationContext = webOperationContext;
  107. this.context = context;
  108. this.pushUserEndpointsRepository = pushUserEndpointsRepository;
  109. this.formsAuth = formsAuth;
  110. this.membershipService = membershipService;
  111. }
  112. private string UserId
  113. {
  114. get
  115. {
  116. string ticketValue = null;
  117. var cookie = this.context.Request.Cookies[this.formsAuth.FormsCookieName];
  118. if (cookie != null)
  119. {
  120. // From cookie.
  121. ticketValue = cookie.Value;
  122. }
  123. else if (this.context.Request.Headers["AuthToken"] != null)
  124. {
  125. // From HTTP header.
  126. ticketValue = this.context.Request.Headers["AuthToken"];
  127. }
  128. if (!string.IsNullOrEmpty(ticketValue))
  129. {
  130. FormsAuthenticationTicket ticket;
  131. try
  132. {
  133. ticket = this.formsAuth.Decrypt(ticketValue);
  134. }
  135. catch
  136. {
  137. throw new WebFaultException<string>("The authorization ticket cannot be decrypted.", HttpStatusCode.Unauthorized);
  138. }
  139. if (ticket != null)
  140. {
  141. return this.membershipService.GetUser(new FormsIdentity(ticket).Name).ProviderUserKey.ToString();
  142. }
  143. else
  144. {
  145. throw new WebFaultException<string>("The authorization token is no longer valid.", HttpStatusCode.Unauthorized);
  146. }
  147. }
  148. else
  149. {
  150. throw new WebFaultException<string>("Resource not found.", HttpStatusCode.NotFound);
  151. }
  152. }
  153. }
  154. #endif
  155. public string Register(PushUserServiceRequest pushUserRegister)
  156. {
  157. // Authenticate.
  158. var userId = this.UserId;
  159. try
  160. {
  161. var pushUserEndpoint = this.pushUserEndpointsRepository.GetPushUserByApplicationAndDevice(pushUserRegister.ApplicationId, pushUserRegister.DeviceId);
  162. if (pushUserEndpoint == null)
  163. {
  164. var newPushUserEndPoint = new PushUserEndpoint(pushUserRegister.ApplicationId, pushUserRegister.DeviceId) { ChannelUri = pushUserRegister.ChannelUri.ToString(), UserId = userId };
  165. this.pushUserEndpointsRepository.AddPushUserEndpoint(newPushUserEndPoint);
  166. }
  167. else
  168. {
  169. // If the user did not change the channel URI, then, there is nothing to update, otherwise, set the new connection status
  170. if (!pushUserEndpoint.ChannelUri.Equals(pushUserRegister.ChannelUri.ToString()) ||
  171. !pushUserEndpoint.UserId.Equals(userId))
  172. {
  173. // Update che channelUri for the UserEndpoint and reset status fields.
  174. pushUserEndpoint.ChannelUri = pushUserRegister.ChannelUri.ToString();
  175. pushUserEndpoint.UserId = userId;
  176. }
  177. this.pushUserEndpointsRepository.UpdatePushUserEndpoint(pushUserEndpoint);
  178. }
  179. }
  180. catch (Exception exception)
  181. {
  182. throw new WebFaultException<string>(
  183. string.Format(CultureInfo.InvariantCulture, "There was an error registering the Push Notification Endpoint: {0}", exception.Message),
  184. HttpStatusCode.InternalServerError);
  185. }
  186. return "Success";
  187. }
  188. public string Unregister(PushUserServiceRequest pushUserUnregister)
  189. {
  190. // Authenticate.
  191. var userId = this.UserId;
  192. try
  193. {
  194. this.pushUserEndpointsRepository.RemovePushUserEndpoint(new PushUserEndpoint(pushUserUnregister.ApplicationId, pushUserUnregister.DeviceId) { UserId = userId });
  195. }
  196. catch (Exception exception)
  197. {
  198. throw new WebFaultException<string>(
  199. string.Format(CultureInfo.InvariantCulture, "There was an error unregistering the Push Notification Endpoint: {0}", exception.Message),
  200. HttpStatusCode.InternalServerError);
  201. }
  202. return "Success";
  203. }
  204. public string[] GetUpdates(string applicationId, string deviceId)
  205. {
  206. // Authenticate.
  207. var userId = this.UserId;
  208. this.webOperationContext.OutgoingResponse.Headers.Add("Cache-Control", "no-cache");
  209. var userEndpoint = this.pushUserEndpointsRepository.GetPushUserByApplicationAndDevice(applicationId, deviceId);
  210. try
  211. {
  212. var queueName = GetQueueName(applicationId, deviceId, userEndpoint.UserId);
  213. var queue = this.cloudQueueClient.GetQueueReference(queueName);
  214. var messages = new List<string>();
  215. if (queue.Exists())
  216. {
  217. var message = queue.GetMessage();
  218. while (message != null)
  219. {
  220. messages.Add(message.AsString);
  221. queue.DeleteMessage(message);
  222. message = queue.GetMessage();
  223. }
  224. }
  225. this.ResetTileNotificationCount(applicationId, deviceId);
  226. return messages.ToArray();
  227. }
  228. catch (Exception exception)
  229. {
  230. throw new WebFaultException<string>(string.Format(CultureInfo.InvariantCulture, "There was an error getting the push notification updates: {0}", exception.Message), HttpStatusCode.InternalServerError);
  231. }
  232. }
  233. private static string GetQueueName(string applicationId, string deviceId, string userId)
  234. {
  235. var uniqueName = string.Concat(applicationId, deviceId, userId);
  236. return string.Concat("notification", uniqueName.GetHashCode());
  237. }
  238. private static CloudStorageAccount GetStorageAccountFromConfigurationSetting()
  239. {
  240. CloudStorageAccount account = null;
  241. try
  242. {
  243. account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
  244. }
  245. catch (InvalidOperationException)
  246. {
  247. account = null;
  248. }
  249. return account;
  250. }
  251. private void ResetTileNotificationCount(string applicationId, string deviceId)
  252. {
  253. var pushUserEndpoint = this.pushUserEndpointsRepository.GetPushUserByApplicationAndDevice(applicationId, deviceId);
  254. pushUserEndpoint.TileCount = 0;
  255. var tile = new TilePushNotificationMessage
  256. {
  257. SendPriority = MessageSendPriority.High,
  258. Count = pushUserEndpoint.TileCount
  259. };
  260. // Send a new tile notification message to reset the count in the phone application.
  261. tile.SendAndHandleErrors(new Uri(pushUserEndpoint.ChannelUri));
  262. // Save the updated count.
  263. this.pushUserEndpointsRepository.UpdatePushUserEndpoint(pushUserEndpoint);
  264. }
  265. }
  266. }