Redth / PushSharp

A server-side library for sending Push Notifications to iOS (iPhone/iPad APNS), Android (C2DM and GCM - Google Cloud Message), Windows Phone, Windows 8, Amazon, Blackberry, and (soon) FirefoxOS devices!
Other
4.38k stars 1.52k forks source link

Apns notification error: 'ConnectionError' System.NullReferenceException #672

Open attilabicsko opened 8 years ago

attilabicsko commented 8 years ago

I'm using PushSharp 4.0.4, installed from NuGet

In the OnNotificationFailed(ApnsNotification, AggregateException) event of the Apns broker, I often get this exception:

PushSharp.Apple.ApnsNotificationException: Apns notification error: 'ConnectionError' ---> System.NullReferenceException: Object reference not set to an instance of an object.

at PushSharp.Apple.ApnsConnection.createBatch(List`1 toSend)
at PushSharp.Apple.ApnsConnection.d__21.MoveNext()

--- End of inner exception stack trace ---
at PushSharp.Apple.ApnsServiceConnection.d__2.MoveNext()

It seems to happen randomly. I'm using PushSharp in a Windows Service, running multiple (>300) brokers in the same time stored in a singleton object's ConcurrentDictionary, if that helps.

Please advise how to troubleshoot this error.

attilabicsko commented 8 years ago

Beside this, sometimes I get the following exception, also in OnNotificationFailed:

System.ArgumentException: Source array was not long enough. Check srcIndex and length, and the array's lower bounds.
at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
at System.Collections.Generic.Queue1.SetCapacity(Int32 capacity) at System.Collections.Generic.Queue1.Enqueue(T item)
at PushSharp.Apple.ApnsConnection.Send(CompletableApnsNotification notification)
at PushSharp.Apple.ApnsServiceConnection.d__2.MoveNext()

Am I doing something wrong or misunderstanding the concept, or could this happen due to a bug?

iinke commented 8 years ago

Same happens for me. It reproduces even with 1 broker, just not so often.

Looks like problem is in ApnsConnection class: notifications queue ( Queue<CompletableApnsNotification> notifications ) isn't thread-safe. I think this queue isn't thread-safe because of timerBatchWait timer: timer's callback executes on a new thread, not the broker thread. If you for example place locks around all places where notifications.Enqueue/notifications.Dequeue is called (lock (notificationBatchQueueLock)), error doesn't seem to reproduce anymore. Should ConcurrentQueue be used instead of Queue here?

mohammadjouhari commented 8 years ago

any update on this. I am getting the same issue right here.

mohammadjouhari commented 8 years ago

@iinke I have a lock statement around the method that it is queening the device tokens. I am also creating batches and Queue device tokens in a timer. So in each 3 seconds I am queering 100 devices. But I am still getting this connection error.

gabrieligbastos commented 8 years ago

Didnt get it. Is it a bug or am I also doing something wrong?

mohammadjouhari commented 8 years ago

@gabrieligbastos it is a bug. Why this error is coming ?

gabrieligbastos commented 8 years ago

I have no clue why? It is just sometimes it just give me back this exception. Seems randomly, Could not find a situation that always happens.

Before update my NugetPackage to the new version, it was not getting this error.

gabrieligbastos commented 8 years ago

Any update to workaround this?

sparity123 commented 8 years ago

I too have the same issue : Connection Error I recently updated pushsharp library to 4.0.10, if i put thread.sleep(1000) in for loop notifications will be sent but it's getting late. Because I need to send notifications to thousands of device tokens. Even for 10 device tokens also not sending without thread.sleep(1000). Please suggest me what's wrong with my code. Here is my code snippet.

public static void SendNotifications(List currentBrandNotications, long brandId) { byte[] appleCert = null;

        string p12File = @"aps_production_brand" + brandId.ToString().Trim() + ".p12";
        try
        {
            appleCert = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "P12\\" + p12File));               
        }
        catch (Exception ex)
        {
            logger.Debug("P12 certificate is not avilable for BrandId: " + brandId);
        }

        try
        {
            logger.Debug(" Send PushNotifications To Apple :- ");

            if (appleCert != null)
            {
                // Configuration
                var config = new ApnsConfiguration(ApnsConfiguration.ApnsServerEnvironment.Production, appleCert, currentBrandNotications[0].P12Password);

                // Create a new broker
                var apnsBroker = new ApnsServiceBroker(config);
                var fbs = new FeedbackService(config);
                // Wire up events
                apnsBroker.OnNotificationFailed += (Notification, aggregateEx) =>
                {
                    //ScheduledNotification ScheduledNotification = new InstantPNScheduler.ScheduledNotification();

                    aggregateEx.Handle(ex =>
                    {
                        // See what kind of exception it was to further diagnose
                        if (ex is ApnsNotificationException)
                        {
                            var notificationException = (ApnsNotificationException)ex;

                            // Deal with the failed notification
                            var apnsNotification = notificationException.Notification;
                            var statusCode = notificationException.ErrorStatusCode;
                            logger.Debug("Apple Notification Failed: ID=" + apnsNotification.Identifier + " Code=" + statusCode);

                        }
                        else
                        {
                            // Inner exception might hold more useful information like an ApnsConnectionException           
                            logger.Debug(ex.InnerException.ToString());
                        }
                        // Mark it as handled
                        return true;
                    });
                };

                apnsBroker.OnNotificationSucceeded += (Notification) =>
                {
                    logger.Debug("Apple Notification Sent!");                  
                };

                // Start the broker
                apnsBroker.Start();  

                foreach (ScheduledNotification notification in currentBrandNotications)
                     {                      
                    try
                    {
                        //logger.Debug("iOS Device token=" + notification.DeviceToken);                                             apnsBroker.QueueNotification(new ApnsNotification
                        {
                               DeviceToken = notification.DeviceToken,
                               Payload = JObject.Parse("{\"aps\":{\"alert\":\"" + notification.Message + "\",\"badge\":1,\"sound\":\"sound.caf\",\"BrandId\":\"" + brandId.ToString() + "\",\"notificationType\":\"Basic\",\"DeviceType\":\"" + notification.DeviceType + "\",\"DeviceToken\":\"" + notification.DeviceToken + "\",\"NotificationId\":\"" + notification.NotificationId + "\"}}")

                            });
                        }
                        Thread.Sleep(800);
                    }
                    catch (Exception ex)
                    {

                        logger.Debug(" SendPushNotificationToApple :- " + ex.Message);
                    }
                }
                // Stop the broker, wait for it to finish   
                // This isn't done after every message, but after you're
                // done with the broker
                apnsBroker.Stop();
            }

        }
        catch (Exception ex)
        {
            logger.Debug("Error" + ex.Message);
        }
        finally
        {
            //apnsBroker = null;
        }

    }

Thanks in advance.

lukaspechar commented 8 years ago

@iinke any updates on this? I experienced this when dealing with a larger batch of notifications. I open the broker and send notification on a separate thread. Could this be the issue? Do you suggest I run the service on the main thread? The following are exceptions logged:

Initially one for every notification:

Source array was not long enough. Check srcIndex and length, and the array's lower bounds.

at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable) at System.Collections.Generic.Queue1.SetCapacity(Int32 capacity) at System.Collections.Generic.Queue1.Enqueue(T item) at PushSharp.Apple.ApnsConnection.Send(CompletableApnsNotification notification) at PushSharp.Apple.ApnsServiceConnection.<Send>d__2.MoveNext()

followed by a bunch of:

The ApnsNotificationErrorStatusCode: ConnectionError = 254,

lukaspechar commented 8 years ago

@Redth Just checking if there are any updates on this issue. I am experiencing this even with a single broker. Would be great to understand what is going on. Any help would be appreciated. Thanks

dehaaneric commented 8 years ago

I had this problem too. I solved it by checking the Push sharp (verbose) logging by setting:

        Log.ClearLoggers();
        Log.AddLogger(new PushLogger());

It showed the error "Missing Push Token". And because I had a device without a (valid) pushtoken on top of my queue, the APNS server disconnected (all) connection(s) without question.

lukaspechar commented 8 years ago

@tweek82 Thanks for your reply. How did you dequeue the device?

dehaaneric commented 8 years ago

I check the push token before I add it to the queue. When token is invalid I directly update the devive in my database by just deleting it.

lukaspechar commented 8 years ago

I am cleaning the expired devices using the FeedbackService class before I add any to the queue. Is there an extra check I need to make? How do you check the validity?

On 4 October 2016 at 16:22, tweek82 notifications@github.com wrote:

I check the push token before I add it to the queue. When token is invalid I directly update the devive in my database by just deleting it.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/Redth/PushSharp/issues/672#issuecomment-251402577, or mute the thread https://github.com/notifications/unsubscribe-auth/AAkJ3F2dvgRN-AUib61wbkhQYtXS9zh4ks5qwmE7gaJpZM4H9ixD .

dehaaneric commented 8 years ago

Nothing fancy, just check IsNullOrWhitespace before queue'ing. Like this:

        foreach (var pushQueueItem in pushQueueItems.WithPrioSorting())
        {
            var pushServiceProviders = PushProviders.Single(x => x.DeviceType == pushQueueItem.AccountDeviceType);

            if (string.IsNullOrWhiteSpace(pushQueueItem.PushRegistrationId))
            {
                CurrentLogger.Logger.Info("Missing devicetoken for: "+JsonConvert.SerializeObject(pushQueueItem));
                PushResultIdCollectorService.AddFailedEntry(pushQueueItem.MessagePushRecipientId, DateTime.Now);

                _accountDeviceService.RemovePushDeviceForRecipient(pushQueueItem.MessagePushRecipientId);

                continue;
            }

            pushServiceProviders.Push(pushQueueItem);
        }
lukaspechar commented 8 years ago

Hmm, ok so you had an empty device token for the device. I guess I'll have to enable the log to monitor what the issue is in my case as I cannot see a reason why my token would be empty or null. I only insert them when the user registers for push notifications from the device. So you used the following to enable logging...

Log.ClearLoggers();
Log.AddLogger(new PushLogger());

I'll give it a go. Thanks for your help and swift replies 👍

dehaaneric commented 8 years ago

No problem. Please share any of your apns-troubles and solutions. It might help me and others too.

lukaspechar commented 8 years ago

Will do, once again thanks for your help @tweek82

bidianqing commented 7 years ago

Apns notification error: 'ConnectionError'

bidianqing commented 7 years ago

IIS Express is Succeeded and IIS is Failed

faisalcse commented 7 years ago

I am getting frequently connection error while sending Push to iOS.

"Failed to Connect, check your firewall settings!

at PushSharp.Apple.ApnsConnection.d25.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at PushSharp.Apple.ApnsConnection.d21.MoveNext() " Sometime it send and sometime it gives error.

Please advice on resolution.

Thanks in Advance.

jimenaju commented 7 years ago

Hello, I seem to be getting the same problem; I send 100 notifications and nothing is wrong, but when one of the tokens is wrong, Ialso get this exception often: PushSharp.Apple.ApnsNotificationException: Apns notification error: 'ConnectionError'

Will insert code but keep in mind a lot of variables are useless, just using them to try to catch the problem...

`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.Web; using System.Text; //using JdSoft.Apple.Apns.Feedback; using PushSharp.Apple; //using Newtonsoft.Json; using Newtonsoft.Json.Linq;

namespace PlaneSeats { public class APNS_Server { //doubts with Code, refer to: //https://stackoverflow.com/questions/37045299/issue-with-pushsharp-apple-notification-from-version-4-0-10-0-to-testflight/37133379

    public void pushNotifiaction(String indicadores)
    {
        string outputString;
        string notificationToken;
        string certificatePath = @"D:\Certificados\Certificados 2.p12";
        string certificatePassword = "";
        var config = new ApnsConfiguration(ApnsConfiguration.ApnsServerEnvironment.Sandbox, certificatePath, certificatePassword);

        //----------------------------------get tokens arr START---------------------------------------------------------------

        String token_iPhone = "1d26e6aade3755f3e98c94421dfa77b7576f5c6d203aed03d4b09afeccc43dce";
        String token_iPad = "2268ce35a15ec46aeef3dd2820e227ea5d9e0eaa163ef2cc33197230cdf93866";
        String bad_token_1 = "e85583e571b7fc3b712ffd33085ca10b42c3691500b96151e95dbe9fab5bee80";
        String bad_token_2 = "75343d0295c6345fd1a6283e7bc6bd66c5";
        String bad_token_3 = "75343d0295c6345fd1a6283e7bc6bd66c55650e0cce06bf6c3bd4b7a368fc3c7";

        int arrSize = 5;
        String[] tokenArr = new String[arrSize]; // Initialize.
        tokenArr[0] = token_iPhone;           // Element 1.
        tokenArr[1] = token_iPad;             // Element 2.
        tokenArr[2] = bad_token_1;
        tokenArr[3] = bad_token_2;
        tokenArr[4] = bad_token_3;

        //----------------------------------get tokens arr END-----------------------------------------------------------------

        var apnsBroker = new ApnsServiceBroker(config);
        // Wire up events
            apnsBroker.OnNotificationFailed += (notification, aggregateEx) =>
            {
                outputString = String.Format("Apple Notification Failed Exception");
                aggregateEx.Handle(ex =>
                {
                    // See what kind of exception it was to further diagnose
                    if (ex is ApnsNotificationException)
                    {
                        notificationToken = "";
                        var notificationException = (ApnsNotificationException)ex;
                        ApnsNotificationErrorStatusCode errorCode = notificationException.ErrorStatusCode;
                        // Deal with the failed notification
                        var apnsNotification = notificationException.Notification;
                        var stCode = notificationException.ErrorStatusCode;
                        string statusCode = notificationException.ErrorStatusCode.ToString();
                        outputString = String.Format("Apple Notification Failed: ID={0}, Code=-{1}- Error code -{2}-.",
                        apnsNotification.Identifier, statusCode,errorCode);
                        outputString = statusCode;
                        outputString = notificationException.ErrorStatusCode.ToString();
                        notificationToken = apnsNotification.DeviceToken;
                        outputString = notificationToken;

                    }
                    else
                    {
                            // Inner exception might hold more useful information like an ApnsConnectionException           
                            outputString = String.Format("Apple Notification Failed for some unknown reason : {0}",
                            ex.InnerException);
                    }
                    // Mark it as handled
                    return true;
                });
            };

            apnsBroker.OnNotificationSucceeded += (notification) =>
            {
                notificationToken = "";
                notificationToken = notification.DeviceToken;
                outputString = String.Format("Apple Notification Sent: ID={0}.",
                notification.Identifier);
                outputString = "Apple Notification Sent!";

            };

//--------------------------------FOR LOOP. STARTS HERE-------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------https://github.com/Redth/PushSharp/issues/763

        apnsBroker.Start();
        foreach (String token in tokenArr)
            {
            //http://desarrolloalpha.inegi.org.mx/app/api/indicadores//interna_v1_1/IOSToken/1ds23/2/json/[TU TOKEN]
            try{

                        // Queue a notification to send
                        ApnsNotification notification = new ApnsNotification
                        {       DeviceToken = token,
                                Payload = JObject.Parse("{\"aps\":{\"alert\":\"Jimena is testing apns feedback service!.\",\"badge\":\"1\"}}")
                                };
                         notification.Tag = token;
                         outputString = "Notification queue";
                         apnsBroker.QueueNotification(notification);
                         //apnsBroker.Stop();

            }
                catch (Exception e) {
                outputString = "Notification queue exception";
            }

        }
        apnsBroker.Stop();

//--------------------------------FOR LOOP. ENDS HERE--------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------------------------------------------------------------------- } }

} ` Also... if someone could tell me if the order is correct... I find it reaaally hard to understand as I´m new to... everything coding TT_TT

Thanks!

andrei1152 commented 7 years ago

fixed this problem by setting config.internalBatchSize = int.MaxValue; I think the notification queue is not thread safe and when notifications are divided into batches, adding them to the queue raises this exception

andersemil commented 7 years ago

Same issue here, I think I might have fixed it by locking notificationBatchQueueLock around the dequeueing, like this:

            lock (notificationBatchQueueLock) {
                while (notifications.Count > 0 && toSend.Count < Configuration.InternalBatchSize) {
                    var n = notifications.Dequeue ();
                    toSend.Add (n);
                }
            }
EduardoKSibata commented 6 years ago

Maybe this problem can occur when the token is in invalid format. The token must be with Alphanumerics characters only, no white spaces or something else.. It works for me.

fatim commented 6 years ago

I get the same error running the service in Azure WebApp. Same code works fine on my laptop.