http://www.developer.com/net/net/article.php/3335731/Using-Timers-in-a-Windows-Service.htm
Welcome to the next installment of the .NET Nuts & Bolts column. In one of the prior columns, "Creating a Windows Service in .NET," we looked at the basics of creating a Windows Service. As a result of that article, I received a number of requests about how to create a service that takes an action on a scheduled interval. In this column, we'll get more in depth with Windows Services and explore how to use timers within them. It will involve using classes in the System.ServiceProcess.ServiceBase and System.Timers namespaces, among others. A Windows Service is a long-running application without a user interface or any visual output. They are ideal for server environments where an application needs to continue to run regardless of whether a user is logged into the console or not. Microsoft server products, such as SQL Server and Exchange, are examples of Windows Service applications. For more basic information on Windows Services, refer to the prior .NET Nuts & Bolts column titled "Creating a Windows Service in .NET." A timer is an object that can be used in your applications to cause an event to occur on a specified interval. There are three timer controls available within the Microsoft .NET Framework. Each one has it specific nuances. The three types of timers are as follows: Each of the timers exposes some basic properties and methods that allow you to control its behavior. The Windows.Forms.Timer and Timers.Timer classes expose the same items: The System.Threading.Timer object has different properties and methods for controlling its behavior. We're not going to cover the use of this timer here, so we'll skip the particulars. The following sample code briefly demonstrates the programmatic setup of a timer in the System.Timers namespace. This example uses a Windows console application for simplicity in being able to see the outcome without requiring a lot of setup. Now that we have seen a simple example of using a timer, we'll get more complex and apply them to a Windows Service. The example in the prior column showed the creation and use of a single timer. This time around, we'll spin up a number of threads and execute multiple timers. This will give us the opportunity to show how to set configurations in threads as well. The first thing we'll need to do is create our item that will run as a thread. Then, we'll create the Windows Service to create the threads. Finally, we'll add an installer to handle the installation of the Windows Service. The following sample code contains an object with a single timer. It simply starts and stops the timer and responds to the timer's event when appropriate. Because parameters cannot be passed to threads, we create a class like this and set the properties equal to the values we would want to pass as parameters to the method running as a thread. Each time the event fires for the item, an entry will be written to the Application log. Now, we'll create our service. The service will create a number of threads and execute the StartTimer method of the TimerItem on each thread. We'll add an event log instance to record the start of the service and the timer events. Now, we include the installer to control the installation of the service. If you have any problems getting this to install using the InstallUtil.exe, make sure you are using the InstallUtil.exe for the appropriate version of the .NET Framework you are using. If you have the 1.0 and 1.1 framework installed, there is a chance the InstallUtil.exe will point to the wrong version of the framework; this will result in an error when you try to install your 1.1-based Windows Service. Now you have seen a few ways in which timers can be used in a Windows Service application. Hopefully, those of you who contacted me with questions about how to use a timer in a service application will find this helpful. A few enhancements you can consider to make this more useful for yourself are as follows: The topic of the next column is yet to be determined. If you have something in particular that you would like to see explained here, you could reach me at mstrawmyer@crowechizek.com. Mark Strawmyer, MCSD, MCSE, MCDBA is a Senior Architect of .NET applications for large and mid-size organizations. Mark is a technology leader with Crowe Chizek in Indianapolis, Indiana. He specializes in the architecture, design, and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C#. You can reach Mark at mstrawmyer@crowechizek.com.
Using Timers in a Windows Service
April 5, 2004
Windows Service Recap
What Is a Timer?
Controlling a Timer
Using a System.Timers.Timer Sample Code
using System;namespace ConsoleTimer{ /// <summary> /// Sample class for testing a server based timer. /// </summary> class Class1 { System.Timers.Timer testTimer = new System.Timers.Timer(); /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { Class1 test = new Class1(); test.testTimer.Enabled = true; test.testTimer.Interval = 5000; // Execute timer every // five seconds test.testTimer.Elapsed += new System.Timers.ElapsedEventHandler(test.testTimer_Elapsed); // Sit and wait so we can see some output Console.ReadLine(); } private void testTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { System.Console.WriteLine("myTimer event occurred"); } }}Using a System.Timers.Timer in a Windows Service
TimedItem Sample Code
using System;namespace CodeGuru.TimerService{ /// <summary> /// Demonstrate the use of a timer. /// </summary> public class TimedItem { private System.Diagnostics.EventLog _AppEventLog; private System.Timers.Timer _Timer; private int _Interval = 30000; public int Interval { get { return this._Interval; } set { this._Interval = value; } } private string _Name = ""; public string Name { get { return this._Name; } set { this._Name = value; } } /// <summary> /// Constructor /// </summary> public TimedItem(System.Diagnostics.EventLog AppEventLog) { this._Timer = new System.Timers.Timer(); this._Timer.Elapsed += new System.Timers.ElapsedEventHandler(_Timer_Elapsed); this._Timer.Enabled = false; this._Timer.Interval = this.Interval; this._AppEventLog = AppEventLog; } /// <summary> /// Start the timer. /// </summary> public void StartTimer() { this._Timer.Enabled = true; } /// <summary> /// Stop the timer. /// </summary> public void StopTimer() { this._Timer.Enabled = false; } /* * Respond to the _Timer elapsed event. */ private void _Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { this._AppEventLog.WriteEntry("Time elapsed for " + this.Name, System.Diagnostics.EventLogEntryType.Information); } }}Windows Service Sample Code
using System;using System.Collections;using System.ComponentModel;using System.Data;using System.Diagnostics;using System.ServiceProcess;using System.Threading;namespace CodeGuru.TimerService{ public class TimerService : System.ServiceProcess.ServiceBase { private System.Diagnostics.EventLog _AppEventLog; private Thread[] _WorkerThreads; private TimedItem[] _Timers; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; public TimerService() { // 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; ServicesToRun = new System.ServiceProcess.ServiceBase[] { new TimerService() }; 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() { this._AppEventLog = new System.Diagnostics.EventLog(); ((System.ComponentModel.ISupportInitialize) (this._AppEventLog)).BeginInit(); // // _AppEventLog // this._AppEventLog.Log = "Application"; this._AppEventLog.Source = "TimerService"; // // TimerService // this.ServiceName = "TimerService"; ((System.ComponentModel.ISupportInitialize) (this._AppEventLog)).EndInit(); } /// <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) { this._Timers = new TimedItem[5]; _WorkerThreads = new Thread[5]; for( int i = 0; i < 5; i++ ) { _Timers[i] = new TimedItem(this._AppEventLog); _Timers[i].Name = "Timer #" + i.ToString(); _WorkerThreads[i] = new Thread(new System.Threading.ThreadStart(_Timers[i].StartTimer)); _WorkerThreads[i].Start(); } } /// <summary> /// Stop this service. /// </summary> protected override void OnStop() { for( int i = 0; i < 5; i++ ) { _Timers[i].StopTimer(); } } }}Windows Service Installer Sample Code
using System;using System.Collections;using System.ComponentModel;using System.Configuration.Install;namespace CodeGuru.TimerService{ /// <summary> /// Summary description for ProjectInstaller. /// </summary> [RunInstaller(true)] public class ProjectInstaller : System.Configuration.Install.Installer { private System.ServiceProcess.ServiceProcessInstaller _TimerServiceProcessInstaller; private System.ServiceProcess.ServiceInstaller _TimerServiceInstaller; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; public ProjectInstaller() { // This call is required by the Designer. InitializeComponent(); // TODO: Add any initialization after the // InitializeComponent call } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Component Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this._TimerServiceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller(); this._TimerServiceInstaller = new System.ServiceProcess.ServiceInstaller(); // // _TimerServiceProcessInstaller // this._TimerServiceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem; this._TimerServiceProcessInstaller.Password = null; this._TimerServiceProcessInstaller.Username = null; // // _TimerServiceInstaller // this._TimerServiceInstaller.ServiceName = "TimerService"; this._TimerServiceInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic; // // ProjectInstaller // this.Installers.AddRange(new System.Configuration.Install.Installer[] { this._TimerServiceInstaller, this._TimerServiceProcessInstaller}); } #endregion }}Possible Enhancements
Future Columns
About the Author