title: PushSharp's StopAllServices() hangs as Windows Service
body: <p>I am trying to get PushSharp (2.0.4.0?) to run as a Windows Service.  Each time the service runs and performs a push.QueueNotification(), the applet hangs on the call to stopAPNS(push).  When I run similar code as a Console applications, it runs fine each time (i.e, I am receiving my push notifications).  The console app is based upon the PushSharp.Sample project.</p>
  
  <p>Interestingly, if I start/stop my applet without executing any push.QueueNotification() calls, my service exits properly.  In others, the call to stopAPNS(push) in OnStop() does not hang.  I guess this makes sense...the queue is empty</p>
  
  <p>I have compiled the PushSharp project under .NET 4.0 and 4.5.  In each case, I get the same behavior.</p>
  
  <p>I have provided a sanitized version of my code below.</p>
  
  <p>Any thoughts on why the push.StopAllServices(true) call hangs when run as a Windows Service?</p>
  
  <p>Thanks.</p>
  
  <pre><code>public class PushNoteService : System.ServiceProcess.ServiceBase
  {
  // Initialize global instance of PushBroker service
      private PushBroker push = new PushBroker();
  
      #region Constructor
      public PushNoteService()
      {
          // This call is required by the Windows.Forms Component Designer.
          InitializeComponent();
  
          // TODO: Add any initialization after the InitComponent call
      }
      #endregion
  
      #region Component Designer generated code
  
      // The main entry point for the process
      static void Main()
      {
          System.ServiceProcess.ServiceBase[] ServicesToRun;
  
          // More than one user Service may run within the same process. To add
          // another service to this process, change the following line to
          // create a second service object. For example,
          //
          //   ServicesToRun = new System.ServiceProcess.ServiceBase[] {new PushNoteService(), new MySecondUserService()};
          //
          ServicesToRun = new System.ServiceProcess.ServiceBase[] { new PushNoteService() };
  
          System.ServiceProcess.ServiceBase.Run(ServicesToRun);
      }
  
      #endregion
  
      #region OnStart
      /// &lt;summary&gt;
      /// Set things in motion so your service can do its work.
      /// &lt;/summary&gt;
      protected override void OnStart(string[] args)
      {
          YYLog.Log.Instance.Info("Starting service.");
  
          timer2.Enabled = true;
  
          YYLog.Log.Instance.Info("Starting APNS.");
          startAPNS(push);
      }
      #endregion
  
      #region OnStop
      /// &lt;summary&gt;
      /// Stop this service.
      /// &lt;/summary&gt;
      protected override void OnStop()
      {
          YYLog.Log.Instance.Info("Stopping service.");
  
          // Add code here to perform any tear-down necessary to stop your service.
          timer2.Enabled = false;
  
          YYLog.Log.Instance.Info("Stopping APNS.");
          stopAPNS(push);
  
          // some clean up.
          push = null;
  
          YYLog.Log.Instance.Info("Service stopped.");
      }
      #endregion
  
  
      #region Acess Methods
  
  
      /// &lt;summary&gt;
      /// On Timer_Elasped events, websites are accessed to check status.
      /// &lt;/summary&gt;
      /// &lt;param name="sender"&gt;Sender.&lt;/param&gt;
      /// &lt;param name="e"&gt;E.&lt;/param&gt;
      private void timer2_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
      {
              int count = checkForPushRequest();
              YYLog.Log.Instance.Info("   Count: " + count.ToString());
              if (count &gt; 0)
              {
                  stopAPNS(push);
              }
  
      }
  
      private int checkForPushRequest()
      {
          YYLog.Log.Instance.Info("Processing push notifications...");
  
          int count = 0;
  
          // Get the ConnectionStrings collection.
          ConnectionStringSettings connections = ConfigurationManager.ConnectionStrings["MyDB"];
  
          using (SqlConnection conn = new SqlConnection(connections.ConnectionString))
          {
              conn.Open();
  
              SqlCommand cmd = new SqlCommand("MySP", conn);
              cmd.CommandType = System.Data.CommandType.StoredProcedure;
  
              SqlDataReader dr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
  
              while (dr.Read())
              {
                  // increment counter
                  count++;
  
                  int badgeNumber = 0;
  
                  string deviceToken = Convert.ToString(dr[dr.GetOrdinal("DeviceToken")]);
                  string alertMessage = Convert.ToString(dr[dr.GetOrdinal("AlertMessage")]);
                  if (!dr.IsDBNull(dr.GetOrdinal("BadgeNumber")))
                  {
                      badgeNumber = Convert.ToInt16(dr[dr.GetOrdinal("BadgeNumber")]);
                  }
                  string soundFile = Convert.ToString(dr[dr.GetOrdinal("SoundFile")]);
  
                  // Send out the notification to APNS
                  YYLog.Log.Instance.Trace("  Sending notification to " + deviceToken);
                  sendPush(deviceToken, alertMessage, badgeNumber, soundFile);
              }
  
              dr.Close();
          }
  
          return count;
      }
  
      private void sendPush(string DeviceToken, string AlertMessage, int BadgeNumber, string SoundFile)
      {
          push.QueueNotification(new AppleNotification()
                                     .ForDeviceToken(DeviceToken)
                                     .WithAlert(AlertMessage)
                                     .WithBadge(BadgeNumber)
                                     .WithSound(SoundFile));
  
      }
  
      private void startAPNS(PushBroker push)
      {
          //Wire up the events for all the services that the broker registers
          push.OnNotificationSent += NotificationSent;
          push.OnChannelException += ChannelException;
          push.OnServiceException += ServiceException;
          push.OnNotificationFailed += NotificationFailed;
          push.OnDeviceSubscriptionExpired += DeviceSubscriptionExpired;
          push.OnDeviceSubscriptionChanged += DeviceSubscriptionChanged;
          push.OnChannelCreated += ChannelCreated;
          push.OnChannelDestroyed += ChannelDestroyed;
  
          string appleCertFileName = System.Configuration.ConfigurationManager.AppSettings["APNS_Certificate"];
          var appleCert = File.ReadAllBytes(appleCertFileName);
  
          string appleCertPassword = System.Configuration.ConfigurationManager.AppSettings["APNS_Certificate_Password"];
          bool productionMode = bool.Parse(System.Configuration.ConfigurationManager.AppSettings["APNS_Production_Mode"]);
          push.RegisterAppleService(new ApplePushChannelSettings(productionMode, appleCert, appleCertPassword)); //Extension method
      }
  
      private void stopAPNS(PushBroker push)
      {
          YYLog.Log.Instance.Info("Waiting for Queue to Finish...");
  
          //Stop and wait for the queues to drains
          push.StopAllServices(true);
  
          YYLog.Log.Instance.Info("Queue Finished");
      }
  
      #region Events
      private void DeviceSubscriptionChanged(object sender, string oldSubscriptionId, string newSubscriptionId, INotification notification)
      {
          //Currently this event will only ever happen for Android GCM
          YYLog.Log.Instance.Info("Device Registration Changed:  Old-&gt; " + oldSubscriptionId + "  New-&gt; " + newSubscriptionId + " -&gt; " + notification);
      }
  
      private void NotificationSent(object sender, INotification notification)
      {
          YYLog.Log.Instance.Info("Sent: " + sender + " -&gt; " + notification);
      }
  
      private void NotificationFailed(object sender, INotification notification, Exception notificationFailureException)
      {
          YYLog.Log.Instance.Error("Failure: " + sender + " -&gt; " + notificationFailureException.Message + " -&gt; " + notification);
      }
  
      private void ChannelException(object sender, IPushChannel channel, Exception exception)
      {
          YYLog.Log.Instance.Error("Channel Exception: " + sender + " -&gt; " + exception);
      }
  
      private void ServiceException(object sender, Exception exception)
      {
          YYLog.Log.Instance.Error("Channel Exception: " + sender + " -&gt; " + exception);
      }
  
      private void DeviceSubscriptionExpired(object sender, string expiredDeviceSubscriptionId, DateTime timestamp, INotification notification)
      {
          YYLog.Log.Instance.Info("Device Subscription Expired: " + sender + " -&gt; " + expiredDeviceSubscriptionId);
      }
  
      private void ChannelDestroyed(object sender)
      {
          YYLog.Log.Instance.Info("Channel Destroyed for: " + sender);
      }
  
      private void ChannelCreated(object sender, IPushChannel pushChannel)
      {
          YYLog.Log.Instance.Info("Channel Created for: " + sender);
      }
      #endregion
  
      #endregion
  
  }
  </code></pre>