Mukarram Mukhtar

Windows Service in .NET

 

Creating Windows Service in .NET

 

 

How to create a Window Service in .NET:

In this article I’ll explain how easy it is to create, install a windows service in .NET and how you can perform a few powerful operations on the target machine with the win service.

 

Creation & Coding Window Service:

 

 

So let’s start by creating our win service:

 ·        Start Microsoft Visual Studio 2003 or later.

·        Click Create New Project

·        In New Project dialog box, select Visual C# in Project types panel on left.

·        Select Windows Service in the Templates panel on right.

·        Give a decent physical path and name to your project and select OK.

 

 

 

By doing this, IDE will create a windows service project with a default service class added into it.

 ·        Rename your Service1.cs to srvcIISRestarter.cs.

·        Add an app.config file by right clicking project root node in Solution Explorer.

·        Double click you srvcIISRestarter and change the ServiceName property to IIS Restarter.

·        Select Add Installer link at the bottom of the properties window.

   

 After completing the above steps your Solution Explorer should look something like this:

  

 Double click ProjectInstaller.cs, you’ll see two files serviceInstaller1.cs and serviceProcessInstaller1.cs in the design window. Select serviceInstaller1.cs, in properties windows:

 ·        Change its ServiceName property to IIS Restarter. 

·        Change its StartType property to Automatic. 

 Select serviceProcessInstaller1.cs, change its Account property to LocalSystem.

 Now let’s just quickly add entries in our app.config file and then we’ll move towards coding the service. Add the following entries in your app.config file and make it look like this:

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

<configuration>

      <appSettings>

<add key=ComputerName value=wit-ws52/>

<add key=LogFilePath value=D:\My Work\prjWindowsService\prjWindowsService\bin\Debug\logIISRestarter.log/>

            <add key=HourOfExecution value=01/>

            <add key=TimerElapse value=3600000/>

      </appSettings>

</configuration>

 The first entry is required because for restarting IIS, we need the computer name. Second entry is required because for the complete win service life cycle we want to log its each and every activity. So our win service will create a log file (if it does not already exist) and then start appending text to it as it performs its functionality. HourOfExecution tells what time of the day our win service will perform its operations, 01:00 AM in our example. TimerElapse tells after how many milliseconds service should check whether it’s the time to perform the operations or not, 3600000 milliseconds = 1 hour.

 Now let’s dwell upon the logic behind the win service. In this example we are going to learn how win services can perform some very powerful operations through .NET. The operations we want our win service to perform are:

 ·        Restart IIS.

·        Restart some other win services.

 We want our service to keep residing in the memory and restart IIS and some other win services once everyday. When win service starts, it executes its OnStart event, it’s similar to the page load event of a web page. In OnStart method we’ll start a timer object which will trigger every hour and see if it’s time to perform its operations. If yes, it will call methods to restart IIS and win services, otherwise, it will silently make a log entry and sleep again for another hour. Now let’s take a look at the code of our service, following namespaces are required to complete our operations.

 using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.Linq;

using System.ServiceProcess;

using System.Text;

using System.IO;

using System.Timers;

using System.Configuration;

using System.Threading;

 The purpose of the namespaces is pretty straight forward and no explanation needed so let’s quickly jump to our class level variables:

   private System.Timers.Timer timer = new System.Timers.Timer();

        private DateTime lastExecutionDate = new DateTime();

        private int interval, hourOfExecution;

        StreamWriter streamWriter;

 Timer object will be used as explained previously. lastExecutionDate will keep the date and time when service performed its operations last time successfully. Interval variable is to set timer’s interval property. hourOfExecution is to set at what time service is allowed to perform its operations. Last but not least, streamWriter is for writing each and every step into log file. Now let’s start coding OnStart method of the service.

    // Line numbers are given just for understanding and are not part of actual code

        protected override void OnStart(string[] args)

        {

01          hourOfExecution = 0;

02          lastExecutionDate = DateTime.Now.AddDays(-1);

 

03          timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);

 

04          if (ConfigurationSettings.AppSettings[“HourOfExecution”] == null ||

                !int.TryParse(ConfigurationSettings.AppSettings[“HourOfExecution”], out hourOfExecution) ||

                hourOfExecution < 1)

05              hourOfExecution = 1;

 

            //enabling the timer

06          timer.Enabled = true;

 

            //set interval to app config elapsed time or 60 minute (= 3600000 milliseconds)

07          if (ConfigurationSettings.AppSettings[“TimerElapse”] != null &&

                int.TryParse(ConfigurationSettings.AppSettings[“TimerElapse”], out interval) &&

                interval > 0)

08              timer.Interval = interval;

            else

09              timer.Interval = interval = (1000 * 60 * 60); // 1000 mili second x 60 x 60 = 1 hour

 

10          this.ServiceTask();

 

11          timer.Start();

        }

 

In line 01 the default value of hourOfExecution has been set to 0. Line 02, sets lastExecutionDate to yesterday’s date so that service can execute for the first time we start it. Line 03, sets the event handler method of timer on the elapsed event. Line 04 checks if there is any entry present in app.config for setting hourOfExecution; if yes, it will set in line 04, else, line 05 will set it to default 1:00 AM. Line 06 sets timer enable. Line 07, similar to line 04, checks if there is any entry present in app.config for timer elapse; if yes, it will set timer’s interval property in line 08; else, line 09 sets it to default 1 hour. Line 10 calls the ServiceTask method and line 11 starts our timer. Please note that ServiceStart method is the one which timer will call after every 1 hour, as shown below, and this will be the method which will make decision whether it’s the right time to perform service operation or not.

   private void OnElapsedTime(object source, ElapsedEventArgs e)

        {

            this.ServiceTask();

        }

 This code shows that after every interval of timer, ServiceTask method will be called. Now let’s see what ServiceTask method is doing:

 // Line numbers are given just for understanding and are not part of actual code

        private void ServiceTask()

        {

01           streamWriter = new StreamWriter(ConfigurationSettings.AppSettings[“LogFilePath”], true);

 

02           streamWriter.WriteLine(“Current date: “ + DateTime.Now.ToLongDateString() + ” “ + DateTime.Now.ToLongTimeString());

03          streamWriter.WriteLine(“Last date: “ + lastExecutionDate.ToLongDateString() + ” “ + lastExecutionDate.ToLongTimeString());

04          streamWriter.WriteLine(“DateTime.Now.Hour <= 6:00 AM ==>> “ + DateTime.Now.Hour.ToString() + ” <= 6 = “ + (DateTime.Now.Hour <= 6).ToString());

 

            try

            {

05              if (DateTime.Now >= lastExecutionDate.AddDays(1) && DateTime.Now.Hour >= hourOfExecution && DateTime.Now.Hour <= 6)

                {

06                  lastExecutionDate = DateTime.Now;

07                  this.RestartIIS();

08                  streamWriter.WriteLine(“IIS restarted successfully.”);

09                  this.RestartSQLServerServices();

                }

            }

            catch (Exception exc)

            {

10              streamWriter.WriteLine(exc.ToString());

            }

            finally

            {

11              streamWriter.WriteLine(“————————————“);

12              streamWriter.Flush();

13              streamWriter.Close();

            }

        }

 Let’s discuss this line by line. Line 01 instantiates stream writer and gets the log file’s path from app.config. In line 02, write current date and time in the log file. Line 03 writes the date and time of last execution. Line 04 writes whether hour of the current time is greater than 1 and less than 6. The idea behind this logic is, we want our service to run only once between 1 AM to 6 AM. That is the time when there is no user on the system and server is completely idle. Line 05 checks if a day has passed since last run and current time is greater or equal to 1 AM and current time is less than 6 AM. If yes then line 06 sets the lastExecutionTime to the current time. Line 07 calls the RestartIIS method. Line 08 logs the message “IIS restarted successfully.”. Line 09 calls the RestartSQLServerServices method. In case there is any exception in performing above mentioned tasks, line 10 is there to log all the details of the exception. Finally block simply writes a long line at the end of every log entry, flushes all the text we’ve buffered so far and then closes the streamWriter. So that’s the story of ServiceTask method and now let’s see how RestartIIS method works:

         private void RestartIIS()

        {

            Process iisreset = new Process();

 

            iisreset.StartInfo.FileName = “iisreset.exe”;

            iisreset.StartInfo.Arguments = ConfigurationSettings.AppSettings[“ComputerName”];

 

            iisreset.Start();

            Thread.Sleep(3000); // Give thread some rest

        }

 RestartIIS is a very simple method, the core logic behind this method can be explained in 2 points:

 ·        Instantiate process class.

·        Point it to iisreset.exe.

·        Execute process

 Okay, I mean in 3 points. iisreset.exe is present in windows system32 folder. To access this file you don’t even need to give any path. It’s pretty similar to if you do Start\Run\iisreset ENTER. While IIS restarts, let the thread sleep for a few seconds so that it starts working on services after the system is done with IIS. After seeing how simple it is to restart IIS through .NET, now let’s move to further see the powers of .NET by stopping and starting other win services. I’ve created a method named StopService, this method accepts an argument, serviceName and stops that service. The method code is as follows:

         private void StopService(string serviceName)

        {

            ServiceController sc = new ServiceController(serviceName);

 

            sc.Stop();

            while (sc.Status != ServiceControllerStatus.Stopped)

            {

                Thread.Sleep(1000);

                sc.Refresh();

            }

            streamWriter.WriteLine(serviceName + ” stopped successfully. “ + DateTime.Now.ToLongTimeString());

            Thread.Sleep(3000); // Give thread some rest

        }

 Pretty straight forward, isn’t it? All we need is ServiceController class, champion of handling services. Instantiate that class with the service name and then call object’s Stop method. After that, just to make sure that service really gets stopped we can loop on service status. That’s what while loop is doing. It will stay in the loop until service status is equal to stop. Once the loop is done, make a log entry and then give the thread some rest again. Exactly similar logic I’ve used for StartService method except we’ll loop until service gets started:

         private void StartService(string serviceName)

        {

            ServiceController sc = new ServiceController(serviceName);

 

            sc.Start();

            while (sc.Status != ServiceControllerStatus.Running)

            {

                Thread.Sleep(1000);

                sc.Refresh();

            }

            streamWriter.WriteLine(serviceName + ” started successfully. “ + DateTime.Now.ToLongTimeString());

            Thread.Sleep(3000); // Give thread some rest

        }

 And finally now is the turn for the method who calls the above two methods. For restarting services I’ve chosen SQL Server services, here is the code:

 

        private void RestartSQLServerServices()

        {

01          ServiceController[] scServices;

02          scServices = ServiceController.GetServices();

 

03          foreach (ServiceController scTemp in scServices)

04              if (scTemp.ServiceName == “MSSQLSERVER” ||

                    scTemp.ServiceName == “ReportServer”)

05                  this.StopService(scTemp.ServiceName);

 

06          foreach (ServiceController scTemp in scServices)

07              if (scTemp.ServiceName == “MSSQLSERVER” ||

                    scTemp.ServiceName == “ReportServer” ||

                    scTemp.ServiceName == “SQLSERVERAGENT”)

08                  this.StartService(scTemp.ServiceName);

        }

 The only line that needs explanation is line 02 ServiceController has a static method GetServices which gets all the services (name and other information) currently installed on the system. After we get all the services, we can loop them and choose which one we want to restart. In our case I’m stopping MSSQLSERVER and ReportServer and I’m starting and above two and SQLSERVERAGENT. The reason behind addition of SQLSERVERAGENT is, this service is child service of MSSQLSERVER, when we stop the latter, former stops as well. But this is not the case when we start these services. When parent is started, child does not start automatically, thus we are starting SQLSERVERAGENT explicitly.

 One last thing left here is how to get the name of the service? Click Start\Administrative Tools\Services. Right click the service name and get its properties. Service name is given at the top of the dialog:

  

 

Now we are pretty much done with coding of the service and ready to deploy it. Compile the project and having 0 compile time errors, our service is ready for deployment.

 Deployment of Win Service:

 For deployment we need a command to enter at command prompt. To avoid opening and closing command prompt, I’ve created two batch files, one for installing and the other for uninstalling the service. For this simply go to project directory, in my case:

 

D:\My Work\prjWindowsService

 

Create a text file and save it with as Install.bat, write the following code in it:

 

d:

cd D:\My Work\prjWindowsService\prjWindowsService\bin\Debug 

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe prjWindowsService.exe

 pause

 Create another text file and save it with as Uninstall.bat, write the following code in it:

 d:

 cd D:\My Work\prjWindowsService\prjWindowsService\bin\Debug

 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe prjWindowsService.exe /u

 pause

 Save both the files. Your project directory should look something like this:

  

 Operation of Win Service:

 After that you can double click install.bat to install the service. After installing you need to start the service. Click Start\Administrative Tools\Services in the services list, locate your newly created and installed service, right click on it and select Start as follows:

  

 If your system time is between 1:00 AM to 6:00 AM, your service will create a log file with an entry like the one below and your IIS and SQLServer will get restarted:

  

 

 

 So that’s pretty much it is, win services in .NET, simple and powerful. Should you have any questions regarding this article, please feel free to contact me or write comments to this article.

 ciao…

3 Comments »

  1. Great Article, dude. Have been looking for this material.

    Thanks much.

    Comment by Shujaat — September 12, 2008 @ 10:44 am

  2. Hey great article man..Its really helpful..but i have a doubt..What if i change the timer interval in app config..If service automatically get the latest value or i need to stop and start the service..i enabled the timer in onstart method..

    Thanks,
    Vivek

    Comment by vivek — February 22, 2010 @ 10:18 am

    • Vivek, in this example you’ll have to stop and start the service to pickup new time interval value from app config; but I think you can do quick little changes in the code so that you don’t have to restart the service and it picks up the latest value whenever you change it.

      Comment by Mukarram Mukhtar — February 22, 2010 @ 3:49 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: