C# dotAPNS push notification stops work on server and need to restart server to make it working

Viewed 544

I tried this code to sent push notification in iOS and it's working but only for some duration and then it is not responding from var response = apns.SendAsync(push).Result; and if I need to sent push notification again then I need to restart the server and then it is start working again but only for some duration.

I am using dotAPNS v4.0.30319 NuGet package to sent push notification. I am using amazonaws server.

Here, I am adding a code sample for a bit more clarity.

 public bool SendIOSNotification(Dictionary<string, Dictionary<string, string>> iosDictionary, ILog log = null)
    {
        
        string p8File= HttpContext.Current.Server.MapPath("*******");
        var options = new ApnsJwtOptions()
        {
            BundleId = "*****",
            CertFilePath = p8File, // use either CertContent or CertFilePath, not both
            KeyId = "******",
            TeamId = "*****"
        };
        var apns = ApnsClient.CreateUsingJwt(new HttpClient(new WinHttpHandler()), options);

        var push = new ApplePush(ApplePushType.Alert)
            .AddBadge(1)
            .AddSound("sound.caf");
            foreach (var itemKey in iosDictionary)
        {
            _log.DebugFormat("========== IOS ==========");
            _log.DebugFormat("Device Item {0}", itemKey);
            string payLoadCatgory = string.Empty;

            push.AddCustomProperty("content-available", "1", true)
            
                .AddToken(itemKey.Key.ToString());                              

            foreach (var itemValue in itemKey.Value)
            {
                try
                {
                    if (!itemValue.Key.ToLower().Contains("id"))
                    {
                        push.AddCustomProperty(itemValue.Key, itemValue.Value, true);
                    }
                    else
                    {
                        push.AddCustomProperty(itemValue.Key, Convert.ToInt64(itemValue.Value), true);
                    }

                    if (itemValue.Key.ToLower().Contains("category"))
                    {
                        payLoadCatgory = itemValue.Value;
                    }
                }
                catch (Exception ex)
                {
                    log.Error(string.Format("Error in send Notification to IOS :: DeviceToken is {0}", itemKey.Key));
                }
            }
            try
            {
                _log.Debug("Start send notification");
                var response =  apns.SendAsync(push).Result;
                _log.Debug("Sent notification");
                if (response.IsSuccessful)
                {
                    log.Info(string.Format("An alert push has been successfully sent!"));
                    return true;
                }
                else
                {
                    switch (response.Reason)
                    {
                        case ApnsResponseReason.BadCertificateEnvironment:
                           break;
                     
                        default:
                            throw new ArgumentOutOfRangeException(nameof(response.Reason), response.Reason, null);
                    }
                    log.Error(string.Format("Failed to send a push, APNs reported an error: " + response.ReasonString));
                }
            }
            catch (TaskCanceledException)
            {
                log.Error(string.Format("Failed to send a push: HTTP request timed out."));
            }
            catch (HttpRequestException ex)
            {
                log.Error(string.Format("Failed to send a push. HTTP request failed: " + ex));
            }
            catch (Exception ex)
            {
                log.Error(string.Format("Failed to send a push. HTTP request failed: " + ex));
                return false;
            }
        }
        return false;
    }
1 Answers

You are creating a new ApnsClient instance for each push being sent. Each ApnsClient thus generates its own JWT token when establishing connection with APNs. Creating new JWT tokens more than once per 20 minutes is strictly prohibited, see the official docs (scroll till the very last section).

Here is the extract:

For security, APNs requires you to refresh your token regularly. Refresh your token no more than once every 20 minutes and no less than once every 60 minutes. APNs rejects any request whose token contains a timestamp that is more than one hour old. Similarly, APNs reports an error if you recreate your tokens more than once every 20 minutes. On your provider server, set up a recurring task to recreate your token with a current timestamp. Encrypt the token again and attach it to subsequent notification requests.

To solve your issue, you need to reuse your ApnsClient instance. One way to do that is to make ApnsClient singleton.

Related