C# Windows Service will not listen

I have a C# Windows Service that runs successfully when the service is started. After it runs through the first cycle and completes all of the records from the database table.

Once a new record is delivered on the table it does not do anything. It's running but I do not know what is happening.

Here is what I have:
1. C# Window Server Framework 4.0
2. Service runs and seeks for new records in database table
3. Moves data to a different table location
4. Repeats process.
5. Once database table is empty the service keeps running
6. When a new file is ready in the table the service does not work any longer.

Code included below..

 protected override void OnStart(string[] args)
        {
           

                try
                {
                   

                    _timer.AutoReset = true;
                    _timer.Interval = 10000;  // 10 seconds
                    _timer.Elapsed += OnElapsedEvent;
                    _timer.Start();

                    Constants.Constants.CurrentQueue = "RTD";

                    ThreadStart st = new ThreadStart(ReaderDemo.ReaderMain);
                    threadListener = new Thread(st);


                    servRun = true;


                    string[] lines42 = { "run", "started", "here" };
                    System.IO.File.WriteAllLines(@"C:\Service\started.txt", lines42);

                    threadListener.Start();


                }


                catch (Exception ex)
                {

                    string ErrorMessage = ex.Message;

                }

         

        }

 protected override void OnStop()
        {

            servRun = false;


            string[] lines4 = { "MQProcessing", "started", "here" };
            System.IO.File.WriteAllLines(@"C:\Service\Stop.txt", lines4);

            _timer.Stop();

        }

Any suggestions?

Thanks
jeffreyjseamanAsked:
Who is Participating?
 
Julian HansenCommented:
Ok I have put together a bit of code you can work with. There are two approaches.

1. Create a timer in your OnStart event and set this to call your worker thread every Interval

The cons of this is that if your worker thread takes longer than interval to process you end up with worker processes bumping into each other .

2. The method I proposed above which is to use signalling.

I have posted a project that uses the latter

Another key aspect that was missed is that worker threads and shared resources must be static - worker thread must be static and anything that is shared between the worker thread and the service must be static.

SLN files are zippable - you must first close VS before zipping your project see attached.

In the attached project Add the call to your ReaderDemo.main in the Else part of the DoWork method. That should do it.
EEService.zip
0
 
Julian HansenCommented:
What does this do
ReaderDemo.ReaderMain

Open in new window

It might be that your thread is terminating after it has finished processing the database when it should be sitting in an efficient wait state before checking the database again.
0
 
jeffreyjseamanAuthor Commented:
Sorry, The ReaderDemo will read what is in the table and then Save it via a Stored Procedure call. The Stored Procedure will "Insert the records" from the table into an archive table and keep looping until finished.

Here is the Reader Information..
 class ReaderDemo
    {

        public static void ReaderMain()
        {
            ReaderDemo rd = new ReaderDemo();

            if ((Constants.Constants.CurrentQueue == "RTD"))
            {

                rd.LoadEWS();


            }

        }



        public void LoadEWS()
        {
            SqlDataReader rdr = null;
            SqlConnection con = null;
            SqlCommand cmd = null;

            try
            {


                string ConnectionString = ConfigurationManager.ConnectionStrings["TestConn"].ConnectionString;

                con = new SqlConnection(ConnectionString);
                con.Open();

                // Set up a command with the given query and associate
                // this with the current connection.
                string CommandText = "SELECT RowNumber,LastName,FirstName,City,State,Zipcode" +
                                     "  FROM Customers ";
                cmd = new SqlCommand(CommandText);
                cmd.Connection = con;

                // Execute the query
                rdr = cmd.ExecuteReader();

                while (rdr.Read())
                {


                    int strRowNumber = (int)rdr["RowNumber"];
                    string strLastName = (string)rdr["LastName"];
                    string strFirstName = (string)rdr["FirstName"];
                    string strCity = (string)rdr["City"];
                    string strState = (string)rdr["State"];
                    string strZip = (string)rdr["ZipCode"];

                    //Call Save Row to table
                    Save.Saverow(strRowNumber, strLastName, strFirstName, strCity, strState, strZip);


                }
            }
            catch (Exception ex)
            {

                // Print error message
                //MessageBox.Show(ex.Message);
            }
            finally
            {
                // Close data reader object and database connection
                if (rdr != null)
                    rdr.Close();

                if (con.State == ConnectionState.Open)
                    con.Close();


            }
        }


    }
}



Here is the Save routine call if this helps you better..

 class Save
    {



        public static void Saverow(
                                    int strRowNumber, String strLastName, String strFirstName, String strCity, String strState,
                                    String strZipCode
                                  )
        {




            string conn = ConfigurationManager.ConnectionStrings["TestConn"].ConnectionString;
            System.Data.SqlClient.SqlConnection SqlConn = new SqlConnection(conn);

       

            SqlConn.Open();



            SqlCommand SqlCmd = new SqlCommand();
            SqlCmd.Connection = SqlConn;
            SqlCmd.CommandText = "dbo.ArchiveData";
            SqlCmd.CommandType = CommandType.StoredProcedure;


            SqlCmd.Parameters.AddWithValue("RowNumber", strRowNumber);
            SqlCmd.Parameters.AddWithValue("LastName", strLastName);
            SqlCmd.Parameters.AddWithValue("FirstName", strFirstName);
            SqlCmd.Parameters.AddWithValue("City", strCity);
            SqlCmd.Parameters.AddWithValue("State", strState);
            SqlCmd.Parameters.AddWithValue("ZipCode", strZipCode);
       
       


            try
            {
                SqlCmd.ExecuteNonQuery();
               
            }
            catch (Exception ex)
            {

                string ErrorMessage = ex.Message;
               
            }
            finally
            {
                SqlConn.Close();
                //MQExecutable.Logging.AuditLog("MQMessages Saved to the Database");
            }

            //Return UserID
        }


    }
}

Thanks
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
Julian HansenCommented:
Ok but what happens when the function LoadEWS terminates?

It is going to return to the point where the thread was created and the thread will terminate so the service will no longer have a running thread.

You have to your thread into a wait state after it has finished processing the DB stuff so that the thread remains active - the thread should wait on a timeout and / or a signal from the service stop function that the service is stopping.
0
 
jeffreyjseamanAuthor Commented:
The LoadEWS function finishes it just keeps running via Visual Studios 2010. I have put break points in and nothing gets stopped and it seems to keep running but nothing is happening.

Yes it's suppose to get to the point to kill the thread. I have this in the stop routine.

Let me try the thread into a wait state and I will update you if that fixes it. Thanks for your help.
0
 
Julian HansenCommented:
I think you are misunderstanding me.

Your LoadEWS basically does the following

* define query
* run query
* loop through returned rows
* cleanup
* exit <==== Here is your problem

The function returns and the thread terminates.

you need an outer block that has some sort of efficient wait condition

* while true
  * wait for timeout or stop signal
  * if stop signal break
  * define query
  * run query
  * loop through returned rows
  * cleanup
* end while
* exit
0
 
jeffreyjseamanAuthor Commented:
Thanks for the clarification. You're saying a while boolean statement at the beginning of the statement before the thread is started? perform a stop signal after the cleanup, that way if it gets more data it can be started again. Is that pretty much what you are referring to?

Thanks
0
 
Julian HansenCommented:
No what I am saying is that the thread needs to stay running for the duration of the service. Your current implementation will result in the thread terminating after it has completed the database operation.

You put a while statement around the code you want to run as part of the service.

Inside the while you use one of the wait event functions to wait for a signal or a timeout.

If a timeout occurs the database code will run and when done the while statement will cycle the thread into the wait statement.

Checking for a service stop after the wait terminates is necessary for graceful shutdown of the service. In the code you have posted you are setting a variable "servRun" which I assume is to indicate the service is running / stopped - but you don't appear to use it.

You should put a test for this inside the while immediately after the wait.

You should also put a event signal call inside the stop to wake up the thread so it can terminate.
0
 
jeffreyjseamanAuthor Commented:
JulianH, I attached my source code. I put a Thread.Sleep command in here but in debug it works fine but when I compile the source code to release and try to start the service it doesn't like it.

You will be rewarded the points for your help either way. If you can take a peak at my code and give me an idea what I can do to make it work. Thanks a lot.
0
 
Julian HansenCommented:
Ok, leave it with me for a bit - I don't have access to my compiler right now but as soon as I do I will see if I can knock something together based on your code.
0
 
jeffreyjseamanAuthor Commented:
THanks JulianH. Well appreciated
0
 
Julian HansenCommented:
Can you post all your code?

You have a timer event pointing to OnElapsedEvent but no definition for that - will be easier if I don't have to create all from scratch.
0
 
jeffreyjseamanAuthor Commented:
I attached the files. I couldn't include suo, sln etc; because it doesn't allow you to do that.

I also posted the full zip file of the service if it helps better here.
http://www.ringgoldaysa.org/services/WindowsService.zip

Thanks a lot
WindowsService-3.zip
0
 
Julian HansenCommented:
Ok you should be able to do this

Service.cs
  // Add this member
  public static AutoResetEvent threadWait = new AutoResetEvent(false);
  ...
  // In the stop method add this 
protected override void OnStop()
{
  servRun = false;
  threadWait.Set();
  ...

Open in new window

Then in Reader.cs change ReaderMain to this
        public static void ReaderMain()
        {
            ReaderDemo rd = new ReaderDemo();

            if ((Constants.Constants.CurrentQueue == "RTD"))
            {
                // Work until told to stop
                while(true) {
                    // if signalled then we are done - signalled in Stop method
                    if (Service1.threadWait.WaitOne(20000)) {
                        break;
                    }
                    // if timeout then do work
                    else {
                        rd.LoadEWS();
                        Service1.threadWait.Reset();
                    }
                }
            }
        }

Open in new window

That should do it
0
 
Julian HansenCommented:
And remove the While loop from the Start process - you are just going to end up creating millions of threads ...
0
 
Julian HansenCommented:
Hang fire on the above - a few issues I have found ...
0
 
jeffreyjseamanAuthor Commented:
Thanks I will try this when I get home tonight.
0
 
jeffreyjseamanAuthor Commented:
Thank You so much... I am going to try now.. Either way you are getting the points.. super job
0
 
jeffreyjseamanAuthor Commented:
JulianH, Thank You so much.. This worked beautifully. If there is a way I can reward you additional 500 points let me know because your efforts were absolutely amazing.. Thank You...
0
 
jeffreyjseamanAuthor Commented:
Excellent support. Provided me exactly what I was looking for. Excellent assistance.
0
 
Julian HansenCommented:
You are most welcome - thanks for the points.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.