diff --git a/PushSharp.Apple/ApnsConnection.cs b/PushSharp.Apple/ApnsConnection.cs index 371151b3..689968c5 100644 --- a/PushSharp.Apple/ApnsConnection.cs +++ b/PushSharp.Apple/ApnsConnection.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Net.Sockets; using System.Net.Security; @@ -153,14 +153,26 @@ async Task SendBatch () } } - foreach (var n in toSend) - sent.Add (new SentNotification (n)); + foreach (var n in toSend) { + // If the notification failed validation before being sent (i.e. it was skipped) + if (n.State == NotificationState.Failed) + continue; + + sent.Add(new SentNotification(n)); + } } } catch (Exception ex) { Log.Error ("APNS-CLIENT[{0}]: Send Batch Error: Batch ID={1}, Error={2}", id, batchId, ex); - foreach (var n in toSend) + foreach (var n in toSend) { + // If the notification has already failed, don't fail it again (it's possible it failed validation already) + // - we want the original error intact (and CompleteFailed raises an exception if called twice on the same notification) + if (n.State == NotificationState.Failed) + continue; + + // Fail the notification. n.CompleteFailed (new ApnsNotificationException (ApnsNotificationErrorStatusCode.ConnectionError, n.Notification, ex)); + } } Log.Info ("APNS-Client[{0}]: Sent Batch, waiting for possible response...", id); @@ -185,9 +197,20 @@ byte[] createBatch (List toSend) var batchData = new List (); // Add all the frame data - foreach (var n in toSend) - batchData.AddRange (n.Notification.ToBytes ()); - + foreach (var n in toSend) { + try { + batchData.AddRange (n.Notification.ToBytes ()); + } catch (NotificationException ex) { + // If a notification fails validation, simply fail it and skip + Log.Info("APNS-CLIENT[{0}]: Notification failed validation, failing notification {1}. Batch ID={2}, Error={3}", id, n.Notification.Identifier, batchId, ex); + + // Raise the failed event for this notification so the caller knows it wasn't sent + n.CompleteFailed (new ApnsNotificationException (ApnsNotificationErrorStatusCode.ConnectionError, n.Notification, ex)); + + // Keep adding the other notifications to the batch data to send as we still want to send the others (provided they pass validation themselves) + } + } + return batchData.ToArray (); } @@ -433,6 +456,8 @@ public CompletableApnsNotification (ApnsNotification notification) public ApnsNotification Notification { get; private set; } + public NotificationState State { get; private set; } + TaskCompletionSource completionSource; public Task WaitForComplete () @@ -443,14 +468,23 @@ public Task WaitForComplete () public void CompleteSuccessfully () { completionSource.SetResult (null); + State = NotificationState.Successful; } public void CompleteFailed (Exception ex) { completionSource.SetResult (ex); + State = NotificationState.Failed; } } + public enum NotificationState + { + Pending, + Successful, + Failed + } + /// /// Using IOControl code to configue socket KeepAliveValues for line disconnection detection(because default is toooo slow) ///