public async Task SaveChangesWithMergeAsync(InboxEntity inboxEntity) { const int MaxRetries = 5; Exception lastError = null; for (int i = 0; i < MaxRetries; i++) { try { if (i > 0) { // Attempt to sync up our inboxEntity with the cloud before saving local changes again. // We can drop the result. Just requerying is enough to solve the problem. await this.Get(inboxEntity.RowKey).ExecuteSegmentedAsync(null); } await this.SaveChangesAsync(); return; } catch (DataServiceRequestException ex) { lastError = ex; } } // Rethrow exception. We've failed too many times. ExceptionDispatchInfo.Capture(lastError).Throw(); }
public static InboxEntity Create() { var entity = new InboxEntity(); var rng = RNGCryptoServiceProvider.Create(); var inboxOwnerCode = new byte[CodeLength]; rng.GetBytes(inboxOwnerCode); entity.InboxOwnerCode = Utilities.ToBase64WebSafe(inboxOwnerCode); entity.RowKey = Guid.NewGuid().ToString(); return entity; }
public static InboxEntity Create() { var entity = new InboxEntity(); var rng = RNGCryptoServiceProvider.Create(); var inboxOwnerCode = new byte[CodeLength]; rng.GetBytes(inboxOwnerCode); entity.InboxOwnerCode = Utilities.ToBase64WebSafe(inboxOwnerCode); entity.RowKey = Guid.NewGuid().ToString(); return(entity); }
public void AddObject(InboxEntity entity) { this.AddObject(this.TableName, entity); }
private async Task AlertLongPollWaiterAsync(InboxEntity inbox) { Requires.NotNull(inbox, "inbox"); await this.PushNotifyInboxMessageAsync(inbox); var id = inbox.RowKey; TaskCompletionSource<object> tcs; lock (LongPollWaiters) { if (LongPollWaiters.TryGetValue(id, out tcs)) { LongPollWaiters.Remove(id); } } if (tcs != null) { tcs.TrySetResult(null); } }
private async Task PushNotifyInboxMessageAppleAsync(InboxEntity inbox) { if (MvcApplication.IsApplePushRegistered) { if (!string.IsNullOrEmpty(inbox.ApplePushNotificationGatewayDeviceToken)) { int count = await this.RetrieveInboxItemsCountAsync(inbox.RowKey); MvcApplication.PushBroker.QueueNotification(new AppleNotification() .ForDeviceToken(inbox.ApplePushNotificationGatewayDeviceToken) .WithBadge(count)); } } }
private async Task PushNotifyInboxMessageGoogleAsync(InboxEntity inbox) { if (!string.IsNullOrEmpty(inbox.GoogleCloudMessagingRegistrationId)) { var notifications = new GooglePushNotifications(this.HttpClient, ConfigurationManager.AppSettings["GoogleApiKey"], inbox.GoogleCloudMessagingRegistrationId); bool invalidChannel = false; try { bool successfulPush = await notifications.PushGoogleRawNotificationAsync(CancellationToken.None); invalidChannel |= !successfulPush; } catch (HttpRequestException) { invalidChannel = true; } if (invalidChannel) { inbox.GoogleCloudMessagingRegistrationId = null; this.InboxTable.UpdateObject(inbox); } } }
private async Task PushNotifyInboxMessageWinPhoneAsync(InboxEntity inbox) { if (!string.IsNullOrEmpty(inbox.WinPhone8PushChannelUri)) { var notifications = new WinPhonePushNotifications(this.HttpClient, new Uri(inbox.WinPhone8PushChannelUri)); int count = await this.RetrieveInboxItemsCountAsync(inbox.RowKey); bool invalidChannel = false; try { var pushTile = notifications.PushWinPhoneTileAsync(inbox.WinPhone8TileTemplate, count: count); Task<bool> pushToast = Task.FromResult(false); if (!string.IsNullOrEmpty(inbox.WinPhone8ToastText1) || !string.IsNullOrEmpty(inbox.WinPhone8ToastText2)) { var line1 = string.Format(CultureInfo.InvariantCulture, inbox.WinPhone8ToastText1 ?? string.Empty, count); var line2 = string.Format(CultureInfo.InvariantCulture, inbox.WinPhone8ToastText2 ?? string.Empty, count); if (inbox.LastWinPhone8PushNotificationUtc.HasValue && inbox.LastAuthenticatedInteractionUtc.HasValue && inbox.LastWinPhone8PushNotificationUtc.Value > inbox.LastAuthenticatedInteractionUtc.Value) { // We've sent a toast notification more recently than the user has checked messages, // so there's no reason to send another for now. pushToast = Task.FromResult(true); } else { pushToast = notifications.PushWinPhoneToastAsync(line1, line2); } } Task<bool> pushRaw = Task.FromResult(false); if (!string.IsNullOrEmpty(inbox.WinPhone8PushChannelContent)) { pushRaw = notifications.PushWinPhoneRawNotificationAsync(inbox.WinPhone8PushChannelContent); } await Task.WhenAll(pushTile, pushToast, pushRaw); invalidChannel |= !(pushTile.Result || pushToast.Result || pushRaw.Result); } catch (HttpRequestException) { invalidChannel = true; } if (invalidChannel) { inbox.WinPhone8PushChannelUri = null; inbox.WinPhone8PushChannelContent = null; inbox.WinPhone8ToastText1 = null; inbox.WinPhone8ToastText2 = null; } else { inbox.LastWinPhone8PushNotificationUtc = DateTime.UtcNow; } this.InboxTable.UpdateObject(inbox); } }
private async Task PushNotifyInboxMessageWinStoreAsync(InboxEntity inbox, int failedAttempts = 0) { if (string.IsNullOrEmpty(inbox.ClientPackageSecurityIdentifier) || string.IsNullOrEmpty(inbox.PushChannelUri)) { return; } var client = await this.ClientTable.GetAsync(inbox.ClientPackageSecurityIdentifier); string bearerToken = client.AccessToken; var pushNotifyRequest = new HttpRequestMessage(HttpMethod.Post, inbox.PushChannelUri); pushNotifyRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); pushNotifyRequest.Headers.Add("X-WNS-Type", "wns/raw"); pushNotifyRequest.Content = new StringContent(inbox.PushChannelContent ?? string.Empty); // yes, it's a string, but we must claim it's an octet-stream pushNotifyRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); var response = await this.HttpClient.SendAsync(pushNotifyRequest); if (response.IsSuccessStatusCode) { inbox.LastWindows8PushNotificationUtc = DateTime.UtcNow; this.InboxTable.UpdateObject(inbox); } else { if (failedAttempts == 0) { var authHeader = response.Headers.WwwAuthenticate.FirstOrDefault(); if (authHeader != null) { if (authHeader.Parameter.Contains("Token expired")) { await client.AcquireWnsPushBearerTokenAsync(this.HttpClient); this.ClientTable.UpdateObject(client); await this.ClientTable.SaveChangesAsync(); await this.PushNotifyInboxMessageWinStoreAsync(inbox, failedAttempts + 1); return; } } } // Log a failure. // TODO: code here. } }
private async Task PushNotifyInboxMessageAsync(InboxEntity inbox) { Requires.NotNull(inbox, "inbox"); await Task.WhenAll( this.PushNotifyInboxMessageWinStoreAsync(inbox), this.PushNotifyInboxMessageWinPhoneAsync(inbox), this.PushNotifyInboxMessageGoogleAsync(inbox), this.PushNotifyInboxMessageAppleAsync(inbox)); }