PushSharp的StopAllServices()作为Windows服务挂起

时间:2013-05-23 12:08:30

标签: push-notification pushsharp

我正在尝试将PushSharp(2.0.4.0?)作为Windows服务运行。每次服务运行并执行push.QueueNotification()时,applet都会挂起对stopAPNS(推送)的调用。当我运行类似于控制台应用程序的代码时,它每次运行正常(即,我正在接收我的推送通知)。控制台应用程序基于PushSharp.Sample项目。

有趣的是,如果我在没有执行任何push.QueueNotification()调用的情况下启动/停止我的applet,我的服务就会正常退出。在其他情况下,OnStop()中对stopAPNS(推送)的调用不会挂起。我想这有道理......队列是空的

我已经在.NET 4.0和4.5下编译了PushSharp项目。在每种情况下,我都会得到相同的行为。

我在下面提供了我的代码的清理版本。

关于为什么push.StopAllServices(true)调用在作为Windows服务运行时挂起的任何想法?

感谢。

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
    /// <summary>
    /// Set things in motion so your service can do its work.
    /// </summary>
    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
    /// <summary>
    /// Stop this service.
    /// </summary>
    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


    /// <summary>
    /// On Timer_Elasped events, websites are accessed to check status.
    /// </summary>
    /// <param name="sender">Sender.</param>
    /// <param name="e">E.</param>
    private void timer2_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
            int count = checkForPushRequest();
            YYLog.Log.Instance.Info("   Count: " + count.ToString());
            if (count > 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-> " + oldSubscriptionId + "  New-> " + newSubscriptionId + " -> " + notification);
    }

    private void NotificationSent(object sender, INotification notification)
    {
        YYLog.Log.Instance.Info("Sent: " + sender + " -> " + notification);
    }

    private void NotificationFailed(object sender, INotification notification, Exception notificationFailureException)
    {
        YYLog.Log.Instance.Error("Failure: " + sender + " -> " + notificationFailureException.Message + " -> " + notification);
    }

    private void ChannelException(object sender, IPushChannel channel, Exception exception)
    {
        YYLog.Log.Instance.Error("Channel Exception: " + sender + " -> " + exception);
    }

    private void ServiceException(object sender, Exception exception)
    {
        YYLog.Log.Instance.Error("Channel Exception: " + sender + " -> " + exception);
    }

    private void DeviceSubscriptionExpired(object sender, string expiredDeviceSubscriptionId, DateTime timestamp, INotification notification)
    {
        YYLog.Log.Instance.Info("Device Subscription Expired: " + sender + " -> " + 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

}

1 个答案:

答案 0 :(得分:1)

我们有一个Web应用程序,但我认为解决方案可以是相同的。 我们花了一整天的时间来猜测问题! 最终它出现了错误的Newtonsoft.Json版本 我们解决方案中的一些项目依赖于此库的旧版本,因此我们在Web项目的/ bin文件夹中获取错误版本的运气不佳。