none
Windows Service - Start Time from app.config

    Question

  •  

    Hi

    Have developed a Windows Service using C# language. Using a app.config

    to store  Database ConnectionStrings, Interval Time and reading these

    values from C# code allowing the Client to change these settings

    before deployment.

    Here is app.config code

    <?xml version="1.0" encoding="utf-8"?>

    <configuration>

    <appSettings>

    <!--These values can be changed at Client site before deployment-->

    <add key="SqlconnStr" value="Data Source=mysource;Initial

    Catalog=myCatalog;Integrated Security=True" />

    <add key="OracleConn" value="provider=msdaora;Data Source=opps;User

    ID=myId;Password=myPassword;" />

    <add key="intervalTime" value="60000" />

    <here I like to have a Start Time property that can be accessed from

    code to set the Windows Service Start time >

    </appSettings>

    Reading above values using

    string connStr =

    ConfigurationSettings.AppSettings["SqlconnStr"].ToString();

    All works fine.

    Same way in order to allow the client to alter the Service Start time

    together with Interval Time I like to  add another attribute in

    app.config and use it in my code.

    My question is:

    Is there a property or method that can be used to set Windows Service

    Start time as I did interval time below?

    //set interval to 1 minute (= 60,000 milliseconds)

    timer.Interval = 120000;

    //timer.starttime or something  = value (read the value from

    app.config) --- Here I need your help and suggestion.

    Regards,


    Apriori algorithm [association rule]
    Wednesday, September 10, 2008 3:17 PM

Answers

  • 1. I just noticed that you said that you sat for 10 minutes waiting for the service to start.  As I mentioned before, you can't use an app.config to have a service start itself.  The code I gave you is set up to have the service start whenever, but have the TransferData method run only at the specified time.  This way, your service acts as a sort of "host" for the actual "work" of the service.  You'll still need to start your service. 

    2. Is it possible that you don't have administrator privileges on the computer you're trying to run this application on.  You should try to put a try/catch around the code within the OnStart method, and then log the exception to the event log to see what exception you're receiving.

    try   
    {  
        // all your code currently in the OnStart method  
    }   
    catch (Exception ex)  
    {  
        System.Diagnostics.EventLog.WriteEntry("MyApplication", ex.Message + Environment.NewLine + ex.StackTrace);  
    }  
     

    Post the result here.
    David Morton - http://blog.davemorton.net/
    Thursday, September 11, 2008 2:58 PM
  • I just looked over your code and I'm seeing a couple of issues.


    First, the OnStart is called when a Start command is sent by the Service Control Manager. You should have initialization code here and return as soon as possible.

    Same with the OnStop. It is called when a Stop command is sent by the Service Control Manager and should return in a timely manner.

    You typically get something like 30 seconds to return for either of these events. Otherwise you'll get an error from the SCM complaining that the service took too long to process the Start or Stop. So putting System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); in OnStart is a big problem. During the call to OnStart and OnStop, if you require more time than what is given to you by default, you must call System.ServiceProcess.Servicebase.RequestAdditionalTime(Milliseconds).


    As an example, I will usually create and start a worker thread within the call to OnStart. Then when OnStop is called I will signal the thread to stop and wait for the thread to terminate. During my wait, I will let the SCM know that I need additional time.

    protected ManualResetEvent shutdownEvent = new ManualResetEvent(false);

    protected override void OnStart(string[] args) 
        _serviceThread = new Thread(Run); 
        _serviceThread.Start(); 
     
    protected override void OnStop() 
      // Stop the service thread 
      while (_serviceThread.IsAlive) 
      { 
         // Notify service thread to stop 
         shutdownEvent.Set(); 
     
         this.RequestAdditionalTime(2000); 
         Thread.Sleep(1000);
      }
    }

    protected bool Wait(int milliSecs)
    {
       return !this.shutdownEvent.WaitOne(milliSecs, true);
    }



    From reading your posts and the replies, what I am understanding is that you want to write a service that executes something at a specific time and then after an interval based on that start time. Let me tell you, I've probably written well over 50-60 different services and what you are describing doesn't really fall into any pattern from my experience. Typically services will execute based on one of the following patterns

    • Interval
    • Scheduled Time
    • Monitoring a path, MSMQ, Database table,  Socket
    • Interval/Schedule Time
    Your description sort of falls into the last one, but typically the scheduled time is a window, meaning you want it to execute on an interval but only between a start and end time. For example, you want to run it on an interval during after hours.


    public void Run() 
        do 
        { 
           if (DateTime.Now.Hour >= startHour && DateTime.Now.Hour < endHour)       
           { 
              // Do work 
           } 
        } 
        while (Wait(this.waitDelay)); 


    So while the worker is going to wake up on the interval you specified, it will only execute the real work during the window that you specified.

    Thursday, September 11, 2008 11:58 PM
  • I thought about that too, but failed to mention it.  On my machine, I have no troubles calling Thread.Sleep(Timeout.Infinite), and the machine doesn't complain at all.  So I'm not necessarily sure that the Thread.Sleep is the problem, I think it's your database calls.  To answer your question again.  (Yes, this is the third or fourth time I've answered the same question.), and this time, hopefully I will explain it more clearly.

    You have two things here:

    1. Your service.
    2. Your TransferData method.

    Number 1 can run forever without any problems.  Your client should not care if it runs forever, because it's a service.  It doesn't do anything until you tell it to do anything.
    Number 2 is your "actual work" that needs to be accomplished.  You can control when this actual work is accomplished by using Thread.Sleep and System.Threading.Timer and other timing/threading objects.  This is what you're doing. 

    Make sure you understand clearly the difference between the service and the method.  Your service can run, and not do anything, but your method needs to run at a particular time.  This is what you're trying to accomplish, and the only way to do it is to make sure number 1 is always running, but is aware that at a particular time, it needs to perform number 2.

    David Morton - http://blog.davemorton.net/
    • Marked as answer by Sukumar Raju Friday, September 12, 2008 2:34 PM
    • Unmarked as answer by Sukumar Raju Thursday, September 18, 2008 2:00 PM
    • Marked as answer by Sukumar Raju Thursday, September 18, 2008 4:42 PM
    Friday, September 12, 2008 12:19 PM
  • I never said your service would not run/work. I simply stated that the way you were using the Thread sleep in OnStart was incorrect. OnStart is an event handler for the Start command from the SCM (Service Command Manager). All SCM commands must be processed in a timely manner. If you need more time you are required to request more time from the SCM. This is how the SCM knows your service is processing the command and hasn't died out on it. Otherwise your service status could sit in a "Starting" state since the SCM never got a response that you started successfully. Just take a look at the Status of the service in computer management. In fact in one of your replies you even states that you were getting the following error:

    Could not start the <ServiceName> service on Local Computer.
    Error 1053: The Service did not respond to the start or control request in a timely fashion.


    And this is being caused by your infinite sleep in OnStart. I've been coding Windows services for over 10 years, since the good old days of C++, and the processing of SCM commands has not changed since. Think of it this way, would you put a Thread.Sleep with infinite timeout in a button click event? Treat OnStart and OnStop the same which the exception that if you are going to take a long time you let the SCM know through the use of RequestAdditionalTime. When you return from OnStart the SCM will log in the event logger that the service has been started and mark the service as Started. The same holds true for any of the other SCM commands (Stop, Pause, Restart).



    Regarding the actual starting of the service, yes after you install it you would have to start it by using the Services interface in Computer Management. You can also use net start commands from the command prompt. After that, if you set your service to start automatically it will be started automatically when the OS starts.
    • Edited by Adrian Puente Friday, September 12, 2008 2:52 PM appended
    • Marked as answer by Sukumar Raju Thursday, September 18, 2008 4:42 PM
    Friday, September 12, 2008 2:49 PM
  • Is your service running now? Look at the list of services in computer management. What is the Status of your service say? "Started" or "Starting" ?  If it says "Starting", the the service didn't start properly. Yes, technically your timer is executing and your database processing code will probably run, but it's not good to leave the service in a starting state. Doing so won't let you stop it properly.

    If it says "Starting" then computer management will disable the stop button. You will need to bring up the task manage and kill your process.

    All you need to do is remove the "Thread.Sleep(Timeout.Infinite)" statement that you have at the end of the OnStart method. Once you do this you should see that when you start the service it will not report any error and the Status should change to "Started."



    • Marked as answer by Sukumar Raju Thursday, September 18, 2008 4:42 PM
    Friday, September 12, 2008 3:34 PM
  • Removing it will all the service to start correctly, meaning the SCM won't hang trying to start your service for an extended amount of time. You will then be able to properly stop the service. Leaving that infinite timeout will cause a couple issues. First, when you restart that machine, the start process will be delayed because the SCM will be waiting for the service to start. This can delay the starting of other services as well. Even shutting can be delayed because the service is not in a healthy status. So definately remove it. You'll see that the service will now start and stop properly.
    • Marked as answer by Sukumar Raju Thursday, September 18, 2008 4:41 PM
    Friday, September 12, 2008 3:56 PM

All replies

  • As for having the app.config data actually "start" the service, you can't really do this. Windows starts the service, or you start the service manually.  There's no app.config setting you can put in there to tell the service to start itself. 

    So a good alternative would be to put in a timer in your service code, and have it pull out the value from the app.config, and run the code you want to run at a particular time when that timer runs out.  To do this, you can put a date value in the app.config, and parse it into a datetime in your service.  Once you parse it into the datetime, you can then calculate how long it will be until that time comes around, and start either a Thread.Sleep for that amount of time, or set up some kind of timer. 


    David Morton - http://blog.davemorton.net/
    Wednesday, September 10, 2008 3:32 PM
  • Here's a similar thread on how you can accomplish what I just described.  

    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/ebe5f10b-286e-45f8-8b97-26b24ef55a5e
    David Morton - http://blog.davemorton.net/
    Wednesday, September 10, 2008 3:34 PM
  • Thanks very much. I am not clear on this . Could you suggest by looking at my code please. Please note  I do have Interval Time for the Service and NOW it is require to use StartTime as explained in previous post.

    public partial class myService : ServiceBase

    {

    //Initialize the Timer

    Timer timer = new Timer();

    public myService()

    {

    InitializeComponent();

    }

    protected override void OnStart(string[] args)

    {

    //Calling my method that do some data Transfer

    TransferData();

    //Handle elapsed event

    timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);



    //timer.Interval = System.Convert.ToInt64(ConfigurationManager.AppSettings.Get("TimeInterval"));

    //set interval to 1 minute (= 60,000 milliseconds)

    timer.Interval = Convert.ToInt64(ConfigurationManager.AppSettings["intervalTime"]);

    //enable the timer

    timer.Enabled = true;

    }

    protected override void OnStop()

    {

    timer.Enabled = false;

    }

    //Idea behind the timer is that it sleeps for a specified period (defined by the interval method),

    //and then executes the code specified with the elapsed event.

    // http://www.aspfree.com/c/a/C-Sharp/Timer-Objects-in-Windows-Services-with-C-sharp-dot-NET/3/

    private void OnElapsedTime(object source, ElapsedEventArgs e)

    {

    //calling my method again when Time is elapsed
        TransferData();

    }

    Regards,


    Apriori algorithm [association rule]
    • Edited by Sukumar Raju Wednesday, September 10, 2008 4:15 PM
    Wednesday, September 10, 2008 4:09 PM
  • You're using System.Windows.Forms.Timer, because at the top of your code file, you probably have a statement saying "using System.Windows.Forms;" (I know this because you're calling a non-parameterized constructor on Timer.  Don't use that timer.  Use System.Threading.Timer and construct it on your OnStart, while keeping it class level.
    David Morton - http://blog.davemorton.net/
    Wednesday, September 10, 2008 4:29 PM
  • Thank you for your information. I am using 

    using System.Timers;  please note this is Windows Service, not win forms app.

    could you alter my code (in my post) and comment, may explain how this functionality is achieved.

    Regards,


    Apriori algorithm [association rule]
    Wednesday, September 10, 2008 4:34 PM
  • The following should do it fine.  It's less code.  Beware, I haven't tested this, but this is the general idea.


    public partial class myService : ServiceBase

    {

    //Initialize the Timer

    System.Threading.Timer timer;

    public myService()

    {

    InitializeComponent();

    }

    protected override void OnStart(string[] args)

    {

    int MillsecondsToStart = // however long until your start time.
    timer = new System.Threading.Timer(OnElapsedTime, null, MillsecondsToStartConvert.ToInt32(ConfigurationManager.AppSettings["intervalTime"]);

    System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);


    }

    protected override void OnStop()

    {

    // nothing needed here.

    }

    //Idea behind the timer is that it sleeps for a specified period (defined by the interval method),

    //and then executes the code specified with the elapsed event.

    // http://www.aspfree.com/c/a/C-Sharp/Timer-Objects-in-Windows-Services-with-C-sharp-dot-NET/3/

    private void OnElapsedTime(object source)

    {
        TransferData();

    }


    David Morton - http://blog.davemorton.net/
    Wednesday, September 10, 2008 4:38 PM
  •  Thanks very much in deed.

    Like to double check couple of issues here

    protected
    override void OnStart(string[] args)

    {

    int MillsecondsToStart = // however long until your start time. {{ Is it Start time from app.config?}}
    timer = new System.Threading.Timer(OnElapsedTime, null, MillsecondsToStartConvert.ToInt32(ConfigurationManager.AppSettings["intervalTime"]); {{ Here we are reading IntervalTime from app.config}}

    System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);


    }


    Apriori algorithm [association rule]
    Wednesday, September 10, 2008 4:42 PM
  • Correct. 

    The first parameter is the callback function, whatever you want your timer to do when it elapsed.
    You'll probably need to calculate this out somehow.

    The second is the value to pass into that callback function.  It's the parameter on your method.

    The third parameter is how long of a delay, in milliseconds, to wait before calling the function.

    The fourth parameter is how long to wait after that to re-call the function.

    Check out the constructor definition at:

    http://msdn.microsoft.com/en-us/library/2x96zfy7.aspx
    David Morton - http://blog.davemorton.net/
    Wednesday, September 10, 2008 5:03 PM
  • Thanks.
    My Windows Serice is a simple one just running on a one machine.

    Functionality is:

    1. connects to SQL Server and reads some data
    2. Writes that data into Oracle Tables

    All working with my code just now. Except not having a Start Time functionality from app.config.

    Using your system.Thread.Timer affects in any way my functionality? In other words using your code affects the functionality in anyway?

    REgards,
    Apriori algorithm [association rule]
    Wednesday, September 10, 2008 5:09 PM
  • It shouldn't affect your functionality at all. 
    David Morton - http://blog.davemorton.net/
    Wednesday, September 10, 2008 5:17 PM
  • Thank you.

    protected override void OnStart(string[] args)

    {

    int MillsecondsToStart =
    // however long until your start time. {{ Is it Start time from app.config?}}

    }

    I am not sure what comes up here. could you help me?


    int MillsecondsTostart = ?


    Apriori algorithm [association rule]
    Wednesday, September 10, 2008 6:54 PM
  • When do you want your TransferData() method to execute after you start the service?  Do you want it to start immediately or do you want it to wait for a while?  Do you want it to start at a particular time of day?  Do you want to store the time of day to have the TransferData() function run in the app.config?

    The short answer is, once you construct the timer, the timer will wait the number of milliseconds in that "millisecondsToStart" variable, before it calls the OnElapsedTime method, which will, in turn call TransferData.  That can be calculated many different ways. 

    So, for instance, let's say your client wants to start the process at 10:00 PM, and you have a StartTime tag in the configuration settings:

    string startTimeString = ConfigurationManager.AppSettings["StartTime"];  
     
            DateTime startTime;  
     
            int millisecondsToStart = 0;  
     
            if (DateTime.TryParseExact(startTimeString , "HHmm", CultureInfo.InvariantCulture, DateTimeStyles.None, out startTime))  
            {  
                if (DateTime.Now > startTime)  
                    startTime = startTime.AddDays(1);  
                millisecondsToStart = (int)startTime.Subtract(DateTime.Now).TotalMilliseconds;   
            } 

    In your configuration settings, you'd have to have a key that looks like this:

    <add key="StartTime" value="2200" />


    David Morton - http://blog.davemorton.net/
    Wednesday, September 10, 2008 7:06 PM
  • yes. you are right. I like to start the Service FIRST TIME according to the Start Time in  myapp.Config.exe  

    Then my Windows Service runs same time every 12 OR 24 hrs [it has been already there intervalTime] allowing the client to configure the interval time.

    Over all below code to achieve the functionality? could you double check and inform please

    public partial class myService : ServiceBase

    {

    //Initialize the Timer

    System.Threading.Timer timer;


    public myService()

    {

    InitializeComponent();

    }

    protected override void OnStart(string[] args)

    {


    string startTimeString = ConfigurationManager.AppSettings["StartTime"];  
     
            DateTime startTime;  
     
            int millisecondsToStart = 0;  
     
            if (DateTime.TryParseExact(startTimeString , "HHmm", CultureInfo.InvariantCulture, DateTimeStyles.None, out startTime))  
            {  
                if (DateTime.Now > startTime)  
                    startTime = startTime.AddDays(1);  
                millisecondsToStart = (int)startTime.Subtract(DateTime.Now).TotalMilliseconds;   
            } 



    timer = new System.Threading.Timer(OnElapsedTime, null, MillsecondsToStart, Convert.ToInt32(ConfigurationManager.AppSettings["intervalTime"]);

    System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);

    }

    protected override void OnStop()

    {

    // nothing needed here.

    }

    //Idea behind the timer is that it sleeps for a specified period (defined by the interval method),

    //and then executes the code specified with the elapsed event.

    // http://www.aspfree.com/c/a/C-Sharp/Timer-Objects-in-Windows-Services-with-C-sharp-dot-NET/3/

    private void OnElapsedTime(object source)

    {
        TransferData();

    }




    Apriori algorithm [association rule]
    Wednesday, September 10, 2008 7:22 PM
  • That looks good except for the case-sensitivity with the variable "millisecondsToStart".  As long as you have your key added in your app.config, you should be okay.
    David Morton - http://blog.davemorton.net/
    Wednesday, September 10, 2008 7:32 PM
  • Please check attached code. I think i have done every thing under your guidelines. Have created couple of projects in order to make sure I am not doing anything stupid. My previous code, one without StartTime works fine. Code  provided by you doesn't start  service / work.  

    I have set startTime in app.config and waited 10+ minutes believing the service is going to start and run the TransferData() method. unfortunately. No response. when I manually start servie getting below error in a window.

    Could not start the <ServiceName> service on Local Computer.
    Error 1053: The Service did not respond to the start or control request in a timely fashion.

    1 using System;  
    2 using System.Collections.Generic;  
    3 using System.ComponentModel;  
    4 using System.Data;  
    5 using System.Diagnostics;  
    6 using System.ServiceProcess;  
    7 using System.Text;  
    8  
    9 using System.Data.SqlClient;  
    10 using System.Data.OleDb;  
    11 using System.Globalization;  
    12 using System.Configuration;  
    13  
    14 namespace WorkOrdersService  
    15 {  
    16     public partial class WorkOrdersService : ServiceBase  
    17     {  
    18         //Initialize an instance of Timer  
    19         System.Threading.Timer timer;  
    20           
    21         public WorkOrdersService()  
    22         {  
    23             InitializeComponent();  
    24         }  
    25  
    26         protected override void OnStart(string[] args)  
    27         {  
    28             string startTimeString = ConfigurationSettings.AppSettings["StartTime"].ToString();  
    29  
    30             DateTime startTime;  
    31             int millisecondsToStart = 0;  
    32  
    33             if (DateTime.TryParseExact(startTimeString, "HHmm", CultureInfo.InvariantCulture, DateTimeStyles.None, out startTime))  
    34             {  
    35                 if (DateTime.Now > startTime)  
    36                     startTime = startTime.AddDays(1);  
    37                 millisecondsToStart = (int)startTime.Subtract(DateTime.Now).TotalMilliseconds;  
    38  
    39             }  
    40  
    41             timer = new System.Threading.Timer(OnElapsedTime, null, millisecondsToStart, Convert.ToInt32(ConfigurationSettings.AppSettings["intervalTime"]));  
    42             System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);  
    43  
    44         }  
    45  
    46         protected override void OnStop()  
    47         {  
    48         }  
    49  
    50         //Idea behind the timer is that it sleeps for a specified period (defined by the interval method),  
    51  
    52         //and then executes the code specified with the elapsed event.  
    53  
    54         private void OnElapsedTime(object source)  
    55         {  
    56             TransferData();  
    57  
    58         }  
    59  
    60  
    61  
    62  

    Here is app.config 

    1 <?xml version="1.0" encoding="utf-8" ?> 
    2 <configuration> 
    3   <appSettings> 
    4     <!--These values can be changed to match Client connectionStrings --> 
    5     <add key="SqlconnStr" value="Data Source=mySource;Initial Catalog=myCatalog;Integrated Security=True" /> 
    6     <add key="oraConnection" value="provider=msdaora;Data Source=mySource;User ID=logbook;Password=password;" /> 
    7  
    8     <!-- Interval Time to start the service. Note: 1 minute = 60,000 milliseconds @@ 24Hrs = 86400000 Milli seconds --> 
    9     <add key="intervalTime" value="60000" /> 
    10  
    11     <!--Service Start Time to configure --> 
    12     <add key="StartTime" value="1250" /> 
    13  
    14   </appSettings> 
    15  
    16  
    17 </configuration> 

    Your help and insight is highly appreciated.

     
    Apriori algorithm [association rule]
    Thursday, September 11, 2008 12:10 AM
  • That's odd.  What user are you running under, and what OS are you on?
    David Morton - http://blog.davemorton.net/
    Thursday, September 11, 2008 2:18 PM
  • Thank you. Have been refreshing this since this morning (UK Time). Glad to hear from you.

    user name: mycompanydomain\myusername

    OS is Windows XP professional.

    Regards,
    Apriori algorithm [association rule]
    Thursday, September 11, 2008 2:25 PM
  • Is that the account you're running the service under?

    No problem.  9:30 here in Houston (Hurricane territory)
    David Morton - http://blog.davemorton.net/
    Thursday, September 11, 2008 2:27 PM
  • Yes. It is same account indeed.

    In Services window....myService Status is 'Starting' and startupType 'Automatic' ....(FYI)

    Regards,

     


    Apriori algorithm [association rule]
    Thursday, September 11, 2008 2:31 PM
  • I wish no more hurricanes to disturb you any more..

    we are @ North East Scotland. used to be lot of snow...miserable. Lot better these days due to Global warming i think.

    I got to handover this piece of Service today...your help is very much apprecated since beginning.

    Regards,
    Apriori algorithm [association rule]
    • Edited by Sukumar Raju Thursday, September 11, 2008 2:48 PM
    Thursday, September 11, 2008 2:42 PM
  • 1. I just noticed that you said that you sat for 10 minutes waiting for the service to start.  As I mentioned before, you can't use an app.config to have a service start itself.  The code I gave you is set up to have the service start whenever, but have the TransferData method run only at the specified time.  This way, your service acts as a sort of "host" for the actual "work" of the service.  You'll still need to start your service. 

    2. Is it possible that you don't have administrator privileges on the computer you're trying to run this application on.  You should try to put a try/catch around the code within the OnStart method, and then log the exception to the event log to see what exception you're receiving.

    try   
    {  
        // all your code currently in the OnStart method  
    }   
    catch (Exception ex)  
    {  
        System.Diagnostics.EventLog.WriteEntry("MyApplication", ex.Message + Environment.NewLine + ex.StackTrace);  
    }  
     

    Post the result here.
    David Morton - http://blog.davemorton.net/
    Thursday, September 11, 2008 2:58 PM
  • yes. you are right. I will put more Error handlers in place and get back to you.

    Regards,
    Apriori algorithm [association rule]
    Thursday, September 11, 2008 3:01 PM
  • Yes your code does work. I am sorry.

    I setup break points by adding debugger...Noticed that when data is read from SQL Server Table and inserting into Oracle, when duplicte records exist, that breaks the process and STOPS the service.

    Hope using Try...Catch with your error handler would prevent this and keeps the Service running.
    or would you suggest soemthing else?

    Regards,
    Apriori algorithm [association rule]
    Thursday, September 11, 2008 3:46 PM
  • Try catch should be fine, although I would definately log the error.  If you can figure out how to stop the error in the first place (perhaps by changing your oracle or sql procedures), I would suggest going that route.
    David Morton - http://blog.davemorton.net/
    Thursday, September 11, 2008 3:50 PM
  • I noticed that my Service is stopped when duplicate records are going to be inserted due to Primary key. Is there a way I could still continue the Service without stopping due to any database related bugs?

    I am using Transaction command. which locks the Tables in Oracle and writes data from Sql Server. if the insertion is unsuccessful ( due to duplicate records because of Primary key or some database anamoly), automatically rollback is carried out.

    Here is the message I get when an exception occur in inserting duplicate primary key records into Oracle Table.

    The myService service terminated unexpectedly. It has done this 1 time(s).

    ==============================================================================================
    Being said that I like to convey that above error is unlikely in real time . I mean when I deploy the service at Client site it is unlikely to get duplicate records from SQL Server database because I have a condition in WHERE CLAUSE to return records with in  a day (24hrs) (This is actual requirement from client).  so client should make sure Interval Time also 24hrs in app.config file other wise duplicate records will be retrieved from SQL Server . In oracle Tables Time_Stamp is one of composite primary key, so it throws an exception (unique records only allowed). But it is quite feasible with your help to configure 'StartTime' for the Service.

    It may likely that I may need to think of solution when client wants the Interval Time 12hrs / 6hrs. Your suggestion is appreciated.

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Like to confirm couple of issues ( I am sure these are my last queries)

    1) Even though StartTime can be configurable through myService.exe.config, I need to manually start the Service. Service starts running at startTime in configuration file.

    2) Can I copy and take myService.exe , myService.exe.config file to client site and allowing client to change datbase connection strings, StartTime and interTime , then deploy myService.exe using C:\>Installutil myService.exe?
    Does the service picks up altered config settings?

    Thats all I need to know ...
    Regards
    Apriori algorithm [association rule]
    • Edited by Sukumar Raju Thursday, September 11, 2008 8:30 PM
    Thursday, September 11, 2008 6:42 PM
  • I'll answer your last couple of questions, then if you have any more, seeing as how this thread has kind of gone off topic.

    1. Your service can start automatically at windows startup if you set it to start automatically.  The service will now act as a shell for the "work" you want to accomplish.  While the service will be running, technically, it won't run the methods that do the actual work until your predefined time, which is set in the app.config.  Until then, it'll just sleep.

    2. You should be able to take those items to the client site and deploy just fine using installutil.  The service will pick up any changes to the app.config.

    All your other errors seem to be related to your database queries, so you ought to start a new thread regarding those errors, and mark this one as answered.
    David Morton - http://blog.davemorton.net/
    Thursday, September 11, 2008 9:24 PM
  • I just looked over your code and I'm seeing a couple of issues.


    First, the OnStart is called when a Start command is sent by the Service Control Manager. You should have initialization code here and return as soon as possible.

    Same with the OnStop. It is called when a Stop command is sent by the Service Control Manager and should return in a timely manner.

    You typically get something like 30 seconds to return for either of these events. Otherwise you'll get an error from the SCM complaining that the service took too long to process the Start or Stop. So putting System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); in OnStart is a big problem. During the call to OnStart and OnStop, if you require more time than what is given to you by default, you must call System.ServiceProcess.Servicebase.RequestAdditionalTime(Milliseconds).


    As an example, I will usually create and start a worker thread within the call to OnStart. Then when OnStop is called I will signal the thread to stop and wait for the thread to terminate. During my wait, I will let the SCM know that I need additional time.

    protected ManualResetEvent shutdownEvent = new ManualResetEvent(false);

    protected override void OnStart(string[] args) 
        _serviceThread = new Thread(Run); 
        _serviceThread.Start(); 
     
    protected override void OnStop() 
      // Stop the service thread 
      while (_serviceThread.IsAlive) 
      { 
         // Notify service thread to stop 
         shutdownEvent.Set(); 
     
         this.RequestAdditionalTime(2000); 
         Thread.Sleep(1000);
      }
    }

    protected bool Wait(int milliSecs)
    {
       return !this.shutdownEvent.WaitOne(milliSecs, true);
    }



    From reading your posts and the replies, what I am understanding is that you want to write a service that executes something at a specific time and then after an interval based on that start time. Let me tell you, I've probably written well over 50-60 different services and what you are describing doesn't really fall into any pattern from my experience. Typically services will execute based on one of the following patterns

    • Interval
    • Scheduled Time
    • Monitoring a path, MSMQ, Database table,  Socket
    • Interval/Schedule Time
    Your description sort of falls into the last one, but typically the scheduled time is a window, meaning you want it to execute on an interval but only between a start and end time. For example, you want to run it on an interval during after hours.


    public void Run() 
        do 
        { 
           if (DateTime.Now.Hour >= startHour && DateTime.Now.Hour < endHour)       
           { 
              // Do work 
           } 
        } 
        while (Wait(this.waitDelay)); 


    So while the worker is going to wake up on the interval you specified, it will only execute the real work during the window that you specified.

    Thursday, September 11, 2008 11:58 PM
  •   Hi David

    I think my service is working fine at the moment. what would you suggest on Adrian Puente's comments? Do  I need to consider his comments or change any of my code?

    Hope I am not bothering you with same questions again and again. Just to conclude

    1) Even though there is StartTime for the Service, after Service Installtion I need to start service by selecting Service Right click. Am I right? But the service will gets executed at specified time in app.config.

    please correct me. Thats all i think.


    Regards,
    Apriori algorithm [association rule]
    Friday, September 12, 2008 8:25 AM
  • I thought about that too, but failed to mention it.  On my machine, I have no troubles calling Thread.Sleep(Timeout.Infinite), and the machine doesn't complain at all.  So I'm not necessarily sure that the Thread.Sleep is the problem, I think it's your database calls.  To answer your question again.  (Yes, this is the third or fourth time I've answered the same question.), and this time, hopefully I will explain it more clearly.

    You have two things here:

    1. Your service.
    2. Your TransferData method.

    Number 1 can run forever without any problems.  Your client should not care if it runs forever, because it's a service.  It doesn't do anything until you tell it to do anything.
    Number 2 is your "actual work" that needs to be accomplished.  You can control when this actual work is accomplished by using Thread.Sleep and System.Threading.Timer and other timing/threading objects.  This is what you're doing. 

    Make sure you understand clearly the difference between the service and the method.  Your service can run, and not do anything, but your method needs to run at a particular time.  This is what you're trying to accomplish, and the only way to do it is to make sure number 1 is always running, but is aware that at a particular time, it needs to perform number 2.

    David Morton - http://blog.davemorton.net/
    • Marked as answer by Sukumar Raju Friday, September 12, 2008 2:34 PM
    • Unmarked as answer by Sukumar Raju Thursday, September 18, 2008 2:00 PM
    • Marked as answer by Sukumar Raju Thursday, September 18, 2008 4:42 PM
    Friday, September 12, 2008 12:19 PM
  •  David your help is very much appreciated. Thank you.

    Have a good weekend.


    regards
    Apriori algorithm [association rule]
    Friday, September 12, 2008 2:34 PM
  • I never said your service would not run/work. I simply stated that the way you were using the Thread sleep in OnStart was incorrect. OnStart is an event handler for the Start command from the SCM (Service Command Manager). All SCM commands must be processed in a timely manner. If you need more time you are required to request more time from the SCM. This is how the SCM knows your service is processing the command and hasn't died out on it. Otherwise your service status could sit in a "Starting" state since the SCM never got a response that you started successfully. Just take a look at the Status of the service in computer management. In fact in one of your replies you even states that you were getting the following error:

    Could not start the <ServiceName> service on Local Computer.
    Error 1053: The Service did not respond to the start or control request in a timely fashion.


    And this is being caused by your infinite sleep in OnStart. I've been coding Windows services for over 10 years, since the good old days of C++, and the processing of SCM commands has not changed since. Think of it this way, would you put a Thread.Sleep with infinite timeout in a button click event? Treat OnStart and OnStop the same which the exception that if you are going to take a long time you let the SCM know through the use of RequestAdditionalTime. When you return from OnStart the SCM will log in the event logger that the service has been started and mark the service as Started. The same holds true for any of the other SCM commands (Stop, Pause, Restart).



    Regarding the actual starting of the service, yes after you install it you would have to start it by using the Services interface in Computer Management. You can also use net start commands from the command prompt. After that, if you set your service to start automatically it will be started automatically when the OS starts.
    • Edited by Adrian Puente Friday, September 12, 2008 2:52 PM appended
    • Marked as answer by Sukumar Raju Thursday, September 18, 2008 4:42 PM
    Friday, September 12, 2008 2:49 PM
  • Hi Adrian

    I am confused little and worried. I am new to Windows Services development, have been programming ASP.NET web apps.

    Just now my Service seems to be working fine. please inform is there anything hidden in the code that may break the service? I should make sure all working as expected to meet client requirements before deployment at client site.

    Regards,
    Apriori algorithm [association rule]
    Friday, September 12, 2008 3:21 PM
  • Is your service running now? Look at the list of services in computer management. What is the Status of your service say? "Started" or "Starting" ?  If it says "Starting", the the service didn't start properly. Yes, technically your timer is executing and your database processing code will probably run, but it's not good to leave the service in a starting state. Doing so won't let you stop it properly.

    If it says "Starting" then computer management will disable the stop button. You will need to bring up the task manage and kill your process.

    All you need to do is remove the "Thread.Sleep(Timeout.Infinite)" statement that you have at the end of the OnStart method. Once you do this you should see that when you start the service it will not report any error and the Status should change to "Started."



    • Marked as answer by Sukumar Raju Thursday, September 18, 2008 4:42 PM
    Friday, September 12, 2008 3:34 PM
  • Thank you Adrian.

    My Service Status is 'Starting'. Is removing "Thread.Sleep(Timeout.Infinite)" going to fix any pit falls and run the service as normal or do i need to add/remove my code.

    Regards,


    Apriori algorithm [association rule]
    Friday, September 12, 2008 3:40 PM
  • Removing it will all the service to start correctly, meaning the SCM won't hang trying to start your service for an extended amount of time. You will then be able to properly stop the service. Leaving that infinite timeout will cause a couple issues. First, when you restart that machine, the start process will be delayed because the SCM will be waiting for the service to start. This can delay the starting of other services as well. Even shutting can be delayed because the service is not in a healthy status. So definately remove it. You'll see that the service will now start and stop properly.
    • Marked as answer by Sukumar Raju Thursday, September 18, 2008 4:41 PM
    Friday, September 12, 2008 3:56 PM
  •  Thank you Adrian.

    I have noticed the issue you have mentioned in Service start and Stop. you are right. Have removed System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);

    can get back after my Testing. once again thank you very much for both of your great help David and Adrian.

    Regards,
    • Edited by Sukumar Raju Saturday, September 13, 2008 3:02 PM
    Saturday, September 13, 2008 2:58 PM
  • David

    when clocks go back or forward this code may not work properly?

    we get Time one hour forward (during October) and again some point backward one hour (i think during summer)

    Regards,


    Apriori algorithm [association rule]
    Thursday, September 18, 2008 1:42 PM
  • Restarting the service on those days should solve this issue for you. 

    If you have further questions on this, you need to start a new thread.  This one's gone off track.
    David Morton - http://blog.davemorton.net/
    Thursday, September 18, 2008 2:21 PM
  • can post with all code for your help.

    Thank you
    Apriori algorithm [association rule]
    Thursday, September 18, 2008 4:09 PM
  •  Hi David

    I have posted new thread with new time issue. Please check at 
    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/3557d08d-08bf-4716-b599-ba7d873e01ca

    your help and insight appreciated.


    Apriori algorithm [association rule]
    Thursday, September 18, 2008 4:39 PM