Click here to Skip to main content
16,012,166 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have write a window service in my Windows Form based application.
The windows form application is used to maintain some events and in same project a windows service has been written to send reminder emails. I have created a setup to install both. My problem is that the service is not started when i install in my machine and having following error

Error 1053: The service dis not respond to the start or control request in a timely fashion.


My Code is below


C#
partial class sendAlerts : ServiceBase
    {
        private Timer Schedular;
        public sendAlerts()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            this.WriteToFile("Service started {0}");
            this.ScheduleService();
        }

        protected override void OnStop()
        {
            this.WriteToFile("Service stopped {0}");
            this.Schedular.Dispose();
        }
        public void ScheduleService()
        {
            try
            {
                Schedular = new Timer(new TimerCallback(SchedularCallback));
                string mode = ConfigurationManager.AppSettings["Mode"].ToUpper();
                this.WriteToFile("Service Mode: " + mode + " {0}");

                //Set the Default Time.
                DateTime scheduledTime = DateTime.MinValue;

                if (mode == "DAILY")
                {
                    //Get the Scheduled Time from AppSettings.
                    scheduledTime = DateTime.Parse(ConfigurationManager.AppSettings["ScheduledTime"]);
                    if (DateTime.Now > scheduledTime)
                    {
                        //If Scheduled Time is passed set Schedule for the next day.
                        scheduledTime = scheduledTime.AddDays(1);
                    }
                }

                if (mode.ToUpper() == "INTERVAL")
                {
                    //Get the Interval in Minutes from AppSettings.
                    int intervalMinutes = Convert.ToInt32(ConfigurationManager.AppSettings["IntervalMinutes"]);

                    //Set the Scheduled Time by adding the Interval to Current Time.
                    scheduledTime = DateTime.Now.AddMinutes(intervalMinutes);
                    if (DateTime.Now > scheduledTime)
                    {
                        //If Scheduled Time is passed set Schedule for the next Interval.
                        scheduledTime = scheduledTime.AddMinutes(intervalMinutes);
                    }
                }

                TimeSpan timeSpan = scheduledTime.Subtract(DateTime.Now);
                string schedule = string.Format("{0} day(s) {1} hour(s) {2} minute(s) {3} seconds(s)", timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);

                this.WriteToFile("Simple Service scheduled to run after: " + schedule + " {0}");

                //Get the difference in Minutes between the Scheduled and Current Time.
                int dueTime = Convert.ToInt32(timeSpan.TotalMilliseconds);

                //Change the Timer's Due Time.
                Schedular.Change(dueTime, Timeout.Infinite);
            }
            catch (Exception ex)
            {
                WriteToFile("Error found to send reminder on: {0} " + ex.Message + ex.StackTrace);

                //Stop the Windows Service.
                using (System.ServiceProcess.ServiceController serviceController = new System.ServiceProcess.ServiceController("SimpleService"))
                {
                    serviceController.Stop();
                }
            }
        }

        private void SchedularCallback(object e)
        {
            try
            {
                DataSet ds = new DataSet();
                ds.ReadXml(Environment.CurrentDirectory + @"\App_Data\userCredentials.xml");
                if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
                {
                    foreach (DataRow dr in ds.Tables[0].Rows)
                    {
                        string name = Convert.ToString(dr["user"]);
                        string email = Convert.ToString(dr["emailID"]);
                        WriteToFile("Trying to send remainder to: " + name + " " + email);
                        using (MailMessage mm = new MailMessage(ConfigurationManager.AppSettings["FromMail"].ToString(), email))
                        {
                            mm.Subject = ConfigurationManager.AppSettings["emailSubject"].ToString();
                            mm.Body = string.Format("<b">
                            mm.IsBodyHtml = true;
                            SmtpClient smtp = new SmtpClient();
                            smtp.Host = ConfigurationManager.AppSettings["host"].ToString();
                            smtp.EnableSsl = true;
                            System.Net.NetworkCredential credentials = new System.Net.NetworkCredential();
                            credentials.UserName = ConfigurationManager.AppSettings["FromMail"].ToString();
                            credentials.Password = ConfigurationManager.AppSettings["password"].ToString();
                            smtp.UseDefaultCredentials = true;
                            smtp.Credentials = credentials;
                            smtp.Port = 587;
                            smtp.Send(mm);
                            WriteToFile("Email sent successfully to: " + name + " " + email);
                        }
                    }
                }
                this.ScheduleService();
            }
            catch (Exception ex)
            {
                WriteToFile("Error found to send reminder on: {0} " + ex.Message + ex.StackTrace);

                //Stop the Windows Service.
                using (System.ServiceProcess.ServiceController serviceController = new System.ServiceProcess.ServiceController("SimpleService"))
                {
                    serviceController.Stop();
                }
            }
        }

        private void WriteToFile(string text)
        {
            //AppDomain.CurrentDomain.BaseDirectory + @"\App_Data\log.txt";
            string path = Environment.CurrentDirectory + @"\App_Data\serviceLogs.txt";
            using (StreamWriter writer = new StreamWriter(path, true))
            {
                writer.WriteLine(string.Format(text, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt")));
                writer.Close();
            //}
        }
    }
Posted
Updated 3-Aug-15 21:17pm
v2
Comments
SundararamanS 4-Aug-15 0:31am    
Can you share your log file servicelogs.txt?
Ajay_Saini 4-Aug-15 6:51am    
presently it is just a blank .txt file.
SundararamanS 4-Aug-15 7:21am    
in your onstart you are logging "Service Started", but if your log file is empty then there is something fishy and is your onstart() is not called ??
SundararamanS 4-Aug-15 7:31am    
Please do a unit test of your email sending function and Schedule Service function with your parameters to see if your email sending function is called immediately and if they are working fine...
If the functions are working properly and suppose if the mail sending function is called immediately and if it takes time to do its work try the following
Use P/Invoke to call SetServiceStatus advapi32.dll function and report the status to SCM in OnStart() method
public enum ServiceState
{
SERVICE_STOPPED = 0x00000001,
SERVICE_START_PENDING = 0x00000002,
SERVICE_STOP_PENDING = 0x00000003,
SERVICE_RUNNING = 0x00000004,
SERVICE_CONTINUE_PENDING = 0x00000005,
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007,
}

[StructLayout(LayoutKind.Sequential)]
public struct ServiceStatus
{
public long dwServiceType;
public ServiceState dwCurrentState;
public long dwControlsAccepted;
public long dwWin32ExitCode;
public long dwServiceSpecificExitCode;
public long dwCheckPoint;
public long dwWaitHint;
};

// Update the service state to Start Pending.
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
// Update the service state to Running.
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
SundararamanS 4-Aug-15 8:27am    
Please note that your onstart method should return within 30 seconds otherwise you will get the same error message!!

1 solution

It is not recomended to write any business logic inside the service OnStart() event. Let the service start smoothly with minimum required time. It gives better user experience. If you write any logic inside OnStart() then the service will be in "Starting" state untill the execution finished.
What you can do is move all of your logic into a separate method. Then create a Thread by passing a ThreadStart object created with the newly created method.
C#
//include namespace
using System.Threading;

//extract business logic to a new method
private void ExecuteMyBusiness()
{
   this.WriteToFile("Service started {0}");
   this.ScheduleService();
}

//your changed OnStart() event
protected override void OnStart(string[] args)
{
   Thread myBusinessThread = new Thread(new ThreadStart(ExecuteMyBusiness));
   myBusinessThread.Start();
}


You can give this a try and if it works fine then well and good.
But, this is not all. You need to check in OnStop() for if the thread has not finished the execution of the task assigned to it then it should wait for it to complete.
For that purpose, you need to incorporate following changes-
C#
//declare a global variable to keep track of thead execution status
private bool isThreadRunning= false;

//change the flag as per execution status
private void ExecuteMyBusiness()
{
   isThreadRunning=true;
   this.WriteToFile("Service started {0}");
   this.ScheduleService();
   isThreadRunning=false;
}

//change your OnStop() accordingly
protected override void OnStop()
{
   while(isThreadRunning)
   {
      Thread.Sleep(1000); //wait for 1 second and then try again
   }
   this.WriteToFile("Service stopped {0}");
   this.Schedular.Dispose();
}


Ok. Is that all?
No, but it should resolve your current problem. You need to do various validation but this should be a good approach to start with.

Hopefully, it helps :)
Please let me know, if you have questions or problem in implementing this design.
 
Share this answer
 
v5
Comments
Ajay_Saini 4-Aug-15 12:11pm    
Thanks for educating me.
I have included all your suggestion and successfully installed the Service with Automatic mode. Still my purpose was not accomplish as emails are not sending by the code. I have Debug but not sure what is the issue. I have shared my complete code, can you please have a look on it...

using System;
using System.Data;
using System.ServiceProcess;
using System.IO;
using System.Threading;
using System.Configuration;
using System.Net.Mail;

namespace WindowsServiceCS
{
public partial class Service1 : ServiceBase
{
private Timer Schedular;
//declare a global variable to keep track of thead execution status
private bool isThreadRunning = false;
public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
Thread myBusinessThread = new Thread(new ThreadStart(ExecuteMyBusiness));
myBusinessThread.Start();
}

protected override void OnStop()
{
while (isThreadRunning)
{
Thread.Sleep(1000); //wait for 1 second and then try again
}
this.WriteToFile("Service stopped {0}");
this.Schedular.Dispose();
}

public void ScheduleService()
{
try
{
Schedular = new Timer(new TimerCallback(SchedularCallback));
string mode = ConfigurationManager.AppSettings["Mode"].ToUpper();
this.WriteToFile("Simple Service Mode: " + mode + " {0}");

//Set the Default Time.
DateTime scheduledTime = DateTime.MinValue;

if (mode == "DAILY")
{
//Get the Scheduled Time from AppSettings.
scheduledTime = DateTime.Parse(System.Configuration.ConfigurationManager.AppSettings["ScheduledTime"]);
if (DateTime.Now > scheduledTime)
{
//If Scheduled Time is passed set Schedule for the next day.
scheduledTime = scheduledTime.AddDays(1);
}
}

if (mode.ToUpper() == "INTERVAL")
{
//Get the Interval in Minutes from AppSettings.
int intervalMinutes = Convert.ToInt32(ConfigurationManager.AppSettings["IntervalMinutes"]);

//Set the Scheduled Time by adding the Interval to Current Time.
scheduledTime = DateTime.Now.AddMinutes(intervalMinutes);
if (DateTime.Now > scheduledTime)
{
//If Scheduled Time is passed set Schedule for the next Interval.
scheduledTime = scheduledTime.AddMinutes(intervalMinutes);
}
}

TimeSpan timeSpan = scheduledTime.Subtract(DateTime.Now);
string schedule = string.Format("{0} day(s) {1} hour(s) {2} minute(s) {3} seconds(s)", timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);

this.WriteToFile("Simple Service scheduled to run after: " + schedule + " {0}");

//Get the difference in Minutes between the Scheduled and Current Time.
int dueTime = Convert.ToInt32(timeSpan.TotalMilliseconds);

//Change the Timer's Due Time.
Schedular.Change(dueTime, Timeout.Infinite);
}
catch (Exception ex)
{
WriteToFile("Simple Service Error on: {0} " + ex.Message + ex.StackTrace);

//Stop the Windows Service.
using (System.ServiceProcess.ServiceController serviceController = new System.ServiceProcess.ServiceController("SimpleService"))
{
serviceController.Stop();
}
}
}
Ajay_Saini 4-Aug-15 12:12pm    
//extract business logic to a new method
private void ExecuteMyBusiness()
{
isThreadRunning = true;
this.WriteToFile("Service started {0}");
this.ScheduleService();
isThreadRunning = false;
}

private void SchedularCallback(object e)
{
try
{
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Email", typeof(string));
DataRow dr = dt.NewRow();
dr["Name"] = "Ajay";
dr["Email"] = "xyz@gmail.com";
dt.Rows.Add(dr);
foreach (DataRow row in dt.Rows)
{
string name = row["Name"].ToString();
string email = row["Email"].ToString();
WriteToFile("Trying to send email to: " + name + " " + email);

using (MailMessage mm = new MailMessage("abc@gmail.com", email))
{
mm.Subject = "Birthday Greetings";
mm.Body = string.Format("Happy Birthday {0}<br /><br />Many happy returns of the day.", name);

mm.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.gmail.com";
smtp.EnableSsl = true;
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential();
credentials.UserName = "abc@mail.com";
credentials.Password = "********";
smtp.UseDefaultCredentials = true;
smtp.Credentials = credentials;
smtp.Port = 587;
smtp.Send(mm);
WriteToFile("Email sent successfully to: " + name + " " + email);
}
}
//this.ScheduleService();
}
catch (Exception ex)
{
WriteToFile("Simple Service Error on: {0} " + ex.Message + ex.StackTrace);

//Stop the Windows Service.
using (System.ServiceProcess.ServiceController serviceController = new System.ServiceProcess.ServiceController("SimpleService"))
{
serviceController.Stop();
}
}
}

private void WriteToFile(string text)
{
string path = "D:\\ServiceLog.txt";
using (StreamWriter writer = new StreamWriter(path, true))
{
writer.WriteLine(string.Format(text, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt")));
writer.Close();
}
}
}
}


Here are the keys in app.config
<add key="Mode" value="INTERVAL">
<add key="IntervalMinutes" value="1">
<add key="ScheduledTime" value="20:24:00">
SundararamanS 5-Aug-15 0:08am    
As already mentioned it looks like your email sending function is failing ... It's due to that your service could not start earlier is my guess... Please check your block of code for email and may be you need to set 2 step authentication to authorize your application to use your gmail account. Please check how to authorize your app to be able to automate this..

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900