Solved

C# Windows Service will not listen

Posted on 2013-06-25
21
402 Views
Last Modified: 2013-06-28
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
0
Comment
Question by:jeffreyjseaman
  • 11
  • 10
21 Comments
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39274913
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
 

Author Comment

by:jeffreyjseaman
ID: 39275029
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
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39275170
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
 

Author Comment

by:jeffreyjseaman
ID: 39275691
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
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39276176
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
 

Author Comment

by:jeffreyjseaman
ID: 39276239
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
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39277108
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
 

Author Comment

by:jeffreyjseaman
ID: 39278320
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
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39278514
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
 

Author Comment

by:jeffreyjseaman
ID: 39278856
THanks JulianH. Well appreciated
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39279155
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
 

Author Comment

by:jeffreyjseaman
ID: 39279346
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
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39280510
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
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39280529
And remove the While loop from the Start process - you are just going to end up creating millions of threads ...
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39280540
Hang fire on the above - a few issues I have found ...
0
 

Author Comment

by:jeffreyjseaman
ID: 39280907
Thanks I will try this when I get home tonight.
0
 
LVL 51

Accepted Solution

by:
Julian Hansen earned 500 total points
ID: 39282270
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
 

Author Comment

by:jeffreyjseaman
ID: 39283923
Thank You so much... I am going to try now.. Either way you are getting the points.. super job
0
 

Author Comment

by:jeffreyjseaman
ID: 39285733
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
 

Author Closing Comment

by:jeffreyjseaman
ID: 39285737
Excellent support. Provided me exactly what I was looking for. Excellent assistance.
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39285830
You are most welcome - thanks for the points.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Lots of people ask this question on how to extend the “MembershipProvider” to make use of custom authentication like using existing database or make use of some other way of authentication. Many blogs show you how to extend the membership provider c…
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now