Solved

Re: Problem with Windows Service program (still!)

Posted on 2006-11-21
16
336 Views
Last Modified: 2011-10-03
I spoke too soon! I have been developing and testing the timer with a Console App and this works perfectly with the same "worker" code ( I should explain that the PollDistributionHouses class is in a separate assembly, so the self same code is used for the Windows Service version). However _pdh.Process() is only run once in the Service version.
It looks as if the timer isn't firing om the interval in the Service version.

This is the Console App version :-

static void Main()
{
        AutoResetEvent manualEvent     = new AutoResetEvent(false);
        PollDistributionHouses _pdh = new PollDistributionHouses(autoEvent) ;

// Create the delegate that invokes methods for the timer.
        TimerCallback timerDelegate =
               new TimerCallback(_pdh.Process);
     
// Create a timer that signals the delegate to invoke
// Process after .2 second, and every 15 seconds
// thereafter.

        Timer stateTimer = new Timer(timerDelegate, autoEvent, 200, 15000);
       
         autoEvent.WaitOne() ;
}

/// "Worker class"
public class PollDistributionHouses
{
     private BusinessLogic _BusinessLogic ;
     private int _iCompanyIndex=0 ;
     private int _iNow  ;
     private int _iLastTime = 0 ;
     private int _iMinutes = 0;
     private     AutoResetEvent autoEvent ;

     
     public PollDistributionHouses(AutoResetEvent me)
     {
                     autoEvent = me ;
          _BusinessLogic = new BusinessLogic() ;
          Companies _Companies = new Companies(_BusinessLogic.Data) ;
          foreach (DataRow _CompaniesRow in _BusinessLogic.Data.Companies.DefaultView.Table.Rows)
          {
               try
               {
               }
               catch
               {
               }
               _iCompanyIndex++ ;
          }
     }    


public void Process(object s)
{
     autoEvent.Reset() ;

     _iNow = BusinessLogic.NowMinutes() ;
               
     for (_iCompanyIndex=0; _iCompanyIndex < _BusinessLogic.Data.Companies.DefaultView.Table.Rows.Count ;_iCompanyIndex++ )
     {
          if (_BusinessLogic.Data.Companies[_iCompanyIndex].Uri.Length > 0)
          {
               _iLastTime = int.Parse(_BusinessLogic.Data.Companies[_iCompanyIndex].LastTime) ;
               _iMinutes = int.Parse(_BusinessLogic.Data.Companies[_iCompanyIndex].Minutes) ;
               if (_iNow < _iLastTime) _iLastTime -= (60 * 24) ;
               if (_iNow - _iLastTime >= _iMinutes)
               {
               this.Go(_BusinessLogic, _iCompanyIndex) ;                                   _iLastTime = _iNow ;
               _BusinessLogic.Data.Companies[_iCompanyIndex].LastTime = _iLastTime.ToString() ;
               }
          }
     }
}

and this is the Windows Service Version :-

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using DataAccess;
using ApplicationLogic;
using System.Configuration;
using System.Threading;


namespace MDSWindowsService
{
     public class MDSWindowsService : System.ServiceProcess.ServiceBase
     {
          /// <summary>
          /// Required designer variable.
          /// </summary>
          private System.ComponentModel.Container components = null;
          private AutoResetEvent autoEvent ;
          private PollDistributionHouses _pdh ;

          public MDSWindowsService()
          {
               // This call is required by the Windows.Forms Component Designer.
               InitializeComponent();

               // TODO: Add any initialization after the InitComponent call
          }

          // The main entry point for the process
          static void Main()
          {
               System.ServiceProcess.ServiceBase[] ServicesToRun;
     
               // More than one user Service may run within the same process. To add
               // another service to this process, change the following line to
               // create a second service object. For example,
               //
               //   ServicesToRun = new System.ServiceProcess.ServiceBase[] {new Service1(), new MySecondUserService()};
               //
               ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MDSWindowsService() };

               System.ServiceProcess.ServiceBase.Run(ServicesToRun);
          }

          /// <summary>
          /// Required method for Designer support - do not modify
          /// the contents of this method with the code editor.
          /// </summary>
          private void InitializeComponent()
          {
               components = new System.ComponentModel.Container();
               this.ServiceName = "MDSWindowsService";
          }

          /// <summary>
          /// Clean up any resources being used.
          /// </summary>
          protected override void Dispose( bool disposing )
          {
               if( disposing )
               {
                    if (components != null)
                    {
                         components.Dispose();
                    }
               }
               base.Dispose( disposing );
          }

          /// <summary>
          /// Set things in motion so your service can do its work.
          /// </summary>
          protected override void OnStart(string[] args)
          {
               // TODO: Add code here to start your service.

               autoEvent = new AutoResetEvent(false);
               _pdh = new PollDistributionHouses(autoEvent) ;

               // Create the delegate that invokes methods for the timer.
               TimerCallback timerDelegate =
                    new TimerCallback(_pdh.Process);
     
               // Create a timer that signals the delegate to invoke
               // Process after one second, and every 1000 seconds
               // thereafter.

               Timer stateTimer = new Timer(timerDelegate, autoEvent, 200, 15000);

          }
 
          /// <summary>
          /// Stop this service.
          /// </summary>
          protected override void OnStop()
          {
               // TODO: Add code here to perform any tear-down necessary to stop your service.
               autoEvent.WaitOne() ;
          }
     }
}

I know that I have used AutoResetEvent instead of ManualResetEvent (copied from MSDN), but was happy with it 'cos it worked in the Console App version.

I must be missing something simple ???
0
Comment
Question by:jonskin
  • 6
  • 3
  • 3
  • +3
16 Comments
 
LVL 4

Expert Comment

by:meenasree
ID: 17994429
In the method process autoEvent.set() should be called this will solve the problem
0
 

Author Comment

by:jonskin
ID: 17995176
Thanks for the reply but, unfortunately, that made no difference to the Windows Service operation : it still fired just the once. Furthermore, in the Console App version the change actually kills the timer, so that it only fires once then exits. When I then removed autoEvent.Set() from Process the Console App. went back to correct execution as before.

Actually, I am a bit puzzled by your suggested solution since the examples in MSDN show that autoEvent.Set() is actually used to kill the timer :-

http://msdn2.microsoft.com/en-us/library/system.threading.timer(VS.80).aspx

0
 
LVL 1

Expert Comment

by:LeoVermaak
ID: 17995198
Hi

You are quite correct:

timer.Enabled = true;

I would create the timer in the server contructor:

timer = new Timer();
timer.Interval = Convert.ToDouble(ConfigurationSettings.AppSettings["TimerInterval"].ToString());
timer.Elapsed += new ElapsedEventHandler(OnTimer);
DebugLvl = ConfigurationSettings.AppSettings["DebugLevel"].ToString().ToCharArray(0,6);


and OnStart:

timer.Enabled = true;

I would also to some logging:
EventLog.WriteEntry("Service started:" + this.ReturnLoggingValue(6).ToString());

Hope this help
0
 

Author Comment

by:jonskin
ID: 17996446
"Hope this help"

Sadly ... not a lot, except that you confirm that autoEvent.Set() is not the answer.

Which method do you mean by "server constructor" ?  Also, you appear to be suggesting
a different sort of timer (is this one in Threading?) -  where is the TimerCallback delegate?

I will have a try at some event logging, though.  That might make facilitate debugging.




0
 
LVL 1

Expert Comment

by:LeoVermaak
ID: 17997249
Hi again

I was bite in a rush when I posted my previous reply.

The first thing I would do is change your timer and use the "using System.Timers;".  The reason is that it is a server based timer with a smaller footprint.

You can also manipulate the timer externally if you declare the timer protected or public object of the service class and you pass the "components" variable to your working class.

I always set the oTimer.enabled = false; when the timer event fires and then do the required processing.

The server constructer - I mean service constructer:
public MDSWindowsService()
          {
               // This call is required by the Windows.Forms Component Designer.
               InitializeComponent();

               // TODO: Add any initialization after the InitComponent call
          }

With regards to eventLogging - I can not live without event logging :)
I use a "layer base" event logging methodology e.g.
DebugLevel = "xxx" - DebugLevel = "999"
If the service object is my top object - the value of the first x will determine what logging I do on that object.
The service object call the worker object  - the value of the 2nd x will determine what logging I do on that object.
The worker object call Business objects - the value of the 3rd x will determine what logging I do on that object.

You can create you own eventLogger which you keep on calling in your assemble and specify the value you assign to the method/exec/exception/property call.

Hope this help
0
 

Author Comment

by:jonskin
ID: 17998394
It may well be that the System.Timer is your preference and I will certainly take a look at how to use it. However, I have spent quite a bit of time following the original advice I received (Q_22061348) and would really like to know why that method is not working. I closed Q_22061348 because I thought it was working ( it did with the Console App.) and had to start the question anew here.
I will also look into your advice on event logging - thnx.
0
 
LVL 1

Expert Comment

by:LeoVermaak
ID: 17999380
The problem you have with the console application working and not the service is the service is multi threaded and the execution you assigning when timeout event occurs is 'out side' the service instance.

The console application is a single threaded application by definition and application execution and thus instance reference thread is 'hults' and kept while waiting for the timeout object 'process' the timeout.

The expert can write you an essay on this matter but that is basically the short and sweet of it.

Good luck
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 23

Expert Comment

by:Christopher Kile
ID: 18022856
Your timer is, in fact, constructed in the correct location (the OnStart handler for the service).  There is no need to pass autoEvent as the state object to the timer, but then the way it's referenced in the delegate seems to me to be non-harmful.  I'm a bit time-bound today, but early tomorrow I'll try to create this service myself and see what the cause of the problem might be.

BTW, I do know that System.Threading.Timer sometimes craps out with certain OS versions after 1 to 100 iterations.  Go to support.microsoft.com and search for System.Threading.Timer and see if your OS might be affected (check your service pack level, it's important); if you might be impacted, a new service pack might fix you.
0
 
LVL 22

Expert Comment

by:cookre
ID: 18023553
Windows timer - based on message pump.  Not suitable for services - even if typed Own/Interactive

Thread timer - based on callback.  As a managed object, if you don't keep a reference to it, it goes away.

System timer - based on OS raised event.
0
 

Author Comment

by:jonskin
ID: 18025920
Thanks, cookre, would you like to expand on that comment?
0
 
LVL 23

Expert Comment

by:Christopher Kile
ID: 18030344
I've been unable to duplicate your bug.  My version (using a test object) merrily runs along.

Try explicitly defining Timer as System.Threading.Timer in both the declaration and the New invocation.

Also, try attaching to the service process using the Visual Studio debugger, set a breakpoint on Process(), and trace through it on the first invocation.  Set your start delay (200 in your example) to 15000 to give you 15 seconds to attach to the process and set the breakpoint (set it larger if you are new to trying this).  They way it works:

Load your service project into VS.NET
Start your service
go to the Debug menu and select Processes
find your service in the list of Processes
click the Attach button
Make sure ONLY Common Language Runtime is checked, then hit OK
Hit close
Set your breakpoint on the source line that begins the Process() routine (explicitly include the source in your project, if necessary)
Wait until the breakpoint is hit, then step through.

I believe this will give you some clue as to what is happening.  Also, PLEASE invoke autoEvent.Set() at the end of Process().

BTW, did you check what version/service pack of your OS that you're using?

NOTES:  System.Timer is not recommended by Microsoft for use in Windows Services - System.Threading.Timer is.
0
 
LVL 23

Expert Comment

by:Christopher Kile
ID: 18037956
I stand corrected.  This source certainly has more experience than I do at this sort of thing, and I'd tend to follow his recommendations.  The code you have SHOULD work, but try this link if you've tried everything else and you're still not getting the functionality you require.

http://www.codeguru.com/csharp/.net/cpp_managed/windowsservices/article.php/c6919__1
0
 

Author Comment

by:jonskin
ID: 18067785
0
 
LVL 1

Accepted Solution

by:
Computer101 earned 0 total points
ID: 18320646
PAQed with points refunded (100)

Computer101
EE Admin
0
 

Author Comment

by:jonskin
ID: 18322430
This is what worked - eventually! :-


namespace MDSWindowsService
{
      public class MDSWindowsService : System.ServiceProcess.ServiceBase
      {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            protected Timer timer;
            private System.ComponentModel.Container components = null;
            private PollDistributionHouses _pdh;

            public MDSWindowsService()
            {
                  // This call is required by the Windows.Forms Component Designer.
                  InitializeComponent();

                  // TODO: Add any initialization after the InitComponent call
                  timer = new Timer();
                  timer.Interval = double.Parse(ConfigurationSettings.AppSettings["TimerInterval"].Trim());
                  timer.Elapsed += new ElapsedEventHandler(OnTimer);
            }

            // The main entry point for the process
            static void Main()
            {
                  System.ServiceProcess.ServiceBase[] ServicesToRun;
     
                  // More than one user Service may run within the same process. To add
                  // another service to this process, change the following line to
                  // create a second service object. For example,
                  //
                  //   ServicesToRun = new System.ServiceProcess.ServiceBase[] {new Service1(), new MySecondUserService()};
                  //
                  ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MDSWindowsService() };

                  System.ServiceProcess.ServiceBase.Run(ServicesToRun);
            }

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                  components = new System.ComponentModel.Container();
                  this.ServiceName = "MDSWindowsService";
            }

            protected void OnTimer(Object source, ElapsedEventArgs e)
            {
                  string usrDir = null;      //Directory where files will be
                  
                  TimeSpan diffTSpan = new TimeSpan(1,0,0,0);
                  
                  timer.Stop();
                  string strResult = _pdh.Process() ;
                  if (strResult.Length > 0)
                  {
                        strResult = "MDSWindowsService Failed on DHID "+strResult ;
                        BusinessLogic.NewEventLog (strResult, 27000) ;
                  }
                  timer.Start();
            }


            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            protected override void Dispose( bool disposing )
            {
                  if( disposing )
                  {
                        if (components != null)
                        {
                              components.Dispose();
                        }
                  }
                  base.Dispose( disposing );
            }

            /// <summary>
            /// Set things in motion so your service can do its work.
            /// </summary>
            protected override void OnStart(string[] args)
            {
                  // TODO: Add code here to start your service.

                  _pdh = new PollDistributionHouses() ;
                  OnContinue();
                  BusinessLogic.NewEventLog ("MDSWindowsService Started", 22001) ;
                  //EventLog.WriteEntry("MDSWindowsService Started");
            }
 
            /// <summary>
            /// Stop this service.
            /// </summary>
            protected override void OnStop()
            {
                  // TODO: Add code here to perform any tear-down necessary to stop your service.
                  OnPause();
                  _pdh = null ;
                  BusinessLogic.NewEventLog ("MDSWindowsService Started", 22002) ;
                  //EventLog.WriteEntry("MDSWindowsService Stopped");
            }


            protected override void OnPause()
            {
                  timer.Enabled = false;
            }

            protected override void OnContinue()
            {
                  timer.Enabled = true;
            }


      }
}
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
countAbc challenge 9 59
create an incrementing variable name AutoHotKey 5 80
Windows Service to Receive TCP Packets 4 124
C# Error - Add Failed 12 78
This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
A short article about problems I had with the new location API and permissions in Marshmallow
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

896 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

14 Experts available now in Live!

Get 1:1 Help Now