线程陷入HttpApplication

时间:2013-12-12 19:34:01

标签: c# multithreading wcf iis pushsharp

我有一个从Global.asax文件开始的WCF应用程序,有一个应用程序启动事件,代码如下:

    public class Global : HttpApplication
    {
        private bool isInitialized = false;
        private static readonly ILog log = LogManager.GetLogger(typeof(Global));
        private PushController pushController;
        private Task pushMonitoringTask;

        protected void Application_Start(object sender, EventArgs e)
        {
            Initialize();
            pushMonitoringTask = Task.Run(() => pushController.StartMonitoring());
        }
 ...}

推送控制器:

    public class PushController
    {
        private IRepository<Question> QuestionRepository { get; set; }
        private IRepository<Mobile_Report> ReportRepository { get; set; }

        private readonly string _syncFilePath;

        private readonly string certificatePath;

        private readonly PushBroker _broker;

        private bool _isStopRequired;

        public PushController(IRepository<Question> questionRepository, IRepository<Mobile_Report> reportsRepository, HttpServerUtility server)
        {
            QuestionRepository = questionRepository;
            ReportRepository = reportsRepository;

            _broker = new PushBroker();

            _syncFilePath = server.MapPath("~/SyncFile.txt");
            certificatePath = "My cert path";

            if (!File.Exists(_syncFilePath))
            {
                using (StreamWriter sw = File.AppendText(_syncFilePath))
                {
                    sw.WriteLine(DateTime.Now);
                    sw.Flush();
                }
            }

            _isStopRequired = false;
        }

        public void StartMonitoring()
        {
            var delay = Convert.ToInt32(ConfigurationManager.AppSettings["NewQuestionsMonitoringDelay"]);
            RunPushServices();

            while (!_isStopRequired)
            {
                using (var fileStream = new FileStream(_syncFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                {
                    DateTime lastSyncDate;

                    using (var sw = new StreamReader(fileStream))
                    {
                        lastSyncDate = Convert.ToDateTime(sw.ReadLine());
                    }

                    if (lastSyncDate == default(DateTime))
                    {
                        throw new Exception("Corrupted or missing sync date");
                    }

                    EnqueueNotificationsList(lastSyncDate);

                    using (var sw = new StreamWriter(_syncFilePath, false))
                    {
                        sw.WriteLine(DateTime.Now);
                        sw.Flush();
                    }
                }

                Thread.Sleep(delay * 1000);
            }

            //_broker.StopAllServices();//waits for the queue to drain
        }

        private void RunPushServices()
        {
            _broker.RegisterAppleService(new ApplePushChannelSettings(false, certificatePath, "My cert password"));
            //_broker.RegisterGcmService(new GcmPushChannelSettings("senderId", "sender auth token", "android app package name"));
        }

        private void EnqueueNotificationsList(DateTime lastSyncDate)
        {
            var newQuestions = QuestionRepository.GetAll().Where(q => q.UtcDateCreated >= lastSyncDate);
            var newReports = ReportRepository.GetAll().Where(r => r.CreatedDate >= lastSyncDate);

            EnqueueQuestionsNotifications(newQuestions);
            EnqueueReportsNorifications(newReports);
        }

        private void EnqueueQuestionsNotifications(IEnumerable<Question> newQuestions)
        {
            foreach (var questionGroup in newQuestions.GroupBy(q => q.Mobile_Sample))
            {
                var firstQuestion = questionGroup.First();
                var targetSample = firstQuestion.Mobile_Sample;
                var allSessions = firstQuestion.Mobile_Sample.Mobile_Claim.Mobile_Contact.UserSession;

                var questionsNotificationString = BuildQuestionsNotificationString(targetSample, questionGroup.Count());

                foreach (var userSession in allSessions)
                {
                    switch (userSession.DeviceType)
                    {
                        case (int)DeviceType.IOSDeivce:
                            _broker.QueueNotification(new AppleNotification()
                                .ForDeviceToken(userSession.DeviceToken)
                                .WithAlert(questionsNotificationString)
                                .WithBadge(1)
                                .WithSound("default")
                                .WithCustomItem("PushInfo", "Questions", targetSample.ID));
                            break;
                        //case (int)DeviceType.AndroidDevice:
                        //    _broker.QueueNotification(
                        //        new GcmNotification().ForDeviceRegistrationId(userSession.DeviceToken)
                        //            .WithJson(@"{""alert"":""ITEL Questions"",""badge"":7,""sound"":""sound.caf""}");
                        //    break;
                    }
                }
            }
        }

        private void EnqueueReportsNorifications(IEnumerable<Mobile_Report> newReports)
        {
            foreach (var reportsGroup in newReports.GroupBy(q => q.Mobile_Sample))
            {
                var firstReport = reportsGroup.First();
                var targetSample = firstReport.Mobile_Sample;
                var allSessions = firstReport.Mobile_Sample.Mobile_Claim.Mobile_Contact.UserSession;

                var reportNotificationString = BuildReportNotificationString(targetSample);

                foreach (var userSession in allSessions)
                {
                    switch (userSession.DeviceType)
                    {
                        case (int)DeviceType.IOSDeivce:
                            _broker.QueueNotification(new AppleNotification()
                                .ForDeviceToken(userSession.DeviceToken)
                                .WithAlert(reportNotificationString)
                                .WithBadge(1)
                                .WithSound("default")
                                .WithCustomItem("Target", "Reports", targetSample.ID));
                            break;
                        //case (int)DeviceType.AndroidDevice:
                        //    _broker.QueueNotification(
                        //        new GcmNotification().ForDeviceRegistrationId(userSession.DeviceToken)
                        //            .WithJson(@"{""alert"":""ITEL Questions"",""badge"":7,""sound"":""sound.caf""}");
                        //    break;
                    }
                }
            }
        }

        private string BuildQuestionsNotificationString(Mobile_Sample targetSample, int count)
        {
            var claimLastNameString = !string.IsNullOrEmpty(targetSample.Mobile_Claim.IILastName)
                ? " " + targetSample.Mobile_Claim.IILastName
                : string.Empty;


            var claimNumberString = !string.IsNullOrEmpty(targetSample.Mobile_Claim.ClaimNumber)
                ? " Claim #" + targetSample.Mobile_Claim.ClaimNumber + ", "
                : " Claim # -";

            var areaDamagedString = !string.IsNullOrEmpty(targetSample.AreaDamaged)
                ? " (" + targetSample.AreaDamaged + ")"
                : string.Empty;

            return "You have " + count + " new questions for" + claimLastNameString + claimNumberString + targetSample.Mobile_SampleType.Name + areaDamagedString;
        }

        private string BuildReportNotificationString(Mobile_Sample targetSample)
        {
            var claimLastNameString = !string.IsNullOrEmpty(targetSample.Mobile_Claim.IILastName)
                ? " " + targetSample.Mobile_Claim.IILastName
                : string.Empty;


            var claimNumberString = !string.IsNullOrEmpty(targetSample.Mobile_Claim.ClaimNumber)
                ? " Claim #" + targetSample.Mobile_Claim.ClaimNumber + ", "
                : " Claim # -";

            var areaDamagedString = !string.IsNullOrEmpty(targetSample.AreaDamaged)
                ? " (" + targetSample.AreaDamaged + ")"
                : string.Empty;

            return "You have a new report for" + claimLastNameString + claimNumberString + targetSample.Mobile_SampleType.Name + areaDamagedString;
        }

        public void RequestMonitoringStop()
        {
            _isStopRequired = true;
        }
    }

因此您可以看到我实际上是在Global.asax中启动了一个终止于Application_End的后台任务。问题是线程周期性卡住并且不再继续(可能是静默崩溃或其他任何事情),因此SyncFile不会更新,也没有新的通知被推送到客户端,服务器的主要功能仍在运行虽然,这也是一个棘手的事情 - 我不能在本地重现问题,只有当服务器部署到生产服务器时才会出现,也许在HttpApplication中有一些关于任务的问题,或者我错过了什么?提前谢谢。

1 个答案:

答案 0 :(得分:0)

找到解决方案 - 如果没有20(默认)分钟的请求,网站将进入“空闲”状态,必须编辑IIS设置。

相关问题