Automate routine tasks with .NET's Windows Services
Takeaway: .NET Framework's Windows Services is an excellent application choice when working with administrative tasks or automating routine tasks. See how it allows you to program and schedule system tasks.
I know very few application developers who spend 100 percent of their time with actual programming work. We often have to devote a portion of our time to system maintenance, as well as the usual array of meetings. Find out how the .NET Framework's Windows Services (formerly known as NT services) allows you to program and schedule system tasks.
Welcome to the world of Windows Services
In the past, you had to be proficient in C++ to develop a Windows Service. Thankfully, the .NET platform opens the process to all .NET developers—albeit C#, VB.NET, J#, and so forth. These services can be automatically started when the computer boots, can be paused and restarted, and do not show any user interface.
You can create a service as a Microsoft Visual Studio .NET project, defining code within it that controls what commands are sent to the service and what actions should be taken when those commands are received. Commands sent to a service include starting, pausing, resuming, and stopping the service, and executing custom commands.
After you create and build the application, you can install it by running the command-line utility InstallUtil.exe and passing the path to the service's executable file, or by using Visual Studio's deployment features. You can then use the Services Control Manager to start, stop, pause, resume, and configure your service. Let's take a closer look at Windows Service classes.
Windows Service classes
You can create Windows Services with the help of the ServiceBase class in the System.ServiceProcess namespace. This class contains the following subset of events that interact with the Windows Service Control Manager (SCM):
Only the OnStart event accepts any type of parameter. The main starting point of a Windows Service execution is the Main method, which accepts no parameters. Now you're ready to create your own service.
Creating a Windows Service
At this point, you know which class and events to utilize, so let's create a sample service. Visual Studio .NET makes it simple to create a service using the code of choice:
Now, you can add your own code to the skeleton Visual Studio .NET creates. The next C# code listing includes the code skeleton Visual Studio creates, along with custom code to write information to the Windows Event Log when the associated events are fired. In addition, a constructor (which is the same as class name), dispose, and the point of execution (i.e., the main method) are included as well:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
namespace WindowsService1 {
public class Service1 : System.ServiceProcess.ServiceBase {
private EventLog log = null;
private System.ComponentModel.Container components = null;
public Service1() {
InitializeComponent();
}
static void Main() {
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new
Service1() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
private void InitializeComponent() {
components = new System.ComponentModel.Container();
this.ServiceName = "Service1";
}
protected override void Dispose( bool disposing ) {
if( disposing ) {
if (components != null) {
components.Dispose();
} }
base.Dispose( disposing );
log.WriteEntry("Service dispose",
EventLogEntryType.Information);
log.Close();
}
protected override void OnStart(string[] args) {
log = new EventLog("Builder.com");
log.WriteEntry("Service starting",
EventLogEntryType.Information);
}
protected override void OnStop() {
log.WriteEntry("Service stopping.",
EventLogEntryType.Information);
} } }
The equivalent VB.NET code follows:
imports System.Diagnostics
Imports System.ServiceProcess
Public Class Service1
Inherits System.ServiceProcess.ServiceBase
Private log As EventLog
Public Sub New()
MyBase.New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If (disposing) Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
log.WriteEntry("Service dispose",
EventLogEntryType.Information)
log.Close()
MyBase.Dispose(disposing)
End Sub
<MTAThread()> _
Shared Sub Main()
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
ServicesToRun = New System.ServiceProcess.ServiceBase() {New
Service1}
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
End Sub
Private components As System.ComponentModel.IContainer
Private Sub InitializeComponent()
components = New System.ComponentModel.Container
Me.ServiceName = "Service1"
End Sub
Protected Overrides Sub OnStart(ByVal args() As String)
log = New EventLog("Builder.com")
log.WriteEntry("Service Starting",
EventLogEntryType.Information)
End Sub
Protected Overrides Sub OnStop()
log.WriteEntry("Service Stopping",
EventLogEntryType.Information)
End Sub
End Class
Notice that the code execution entry point (Main method) creates a new instance of the ServiceBase class (an object array) and adds an instance of your class to it. The use of the array demonstrates the ability to run more than one process within the service (notice the thread marker within the VB.NET code).
Windows service installation
While console, Windows Form, and ASP.NET applications are easy to install by copying files, you must explicitly install Windows Service applications. Visual Studio .NET simplifies the installation process for Windows server applications. It displays a link in the Properties window of the Windows Service called Add Installer. When you select the link, the IDE adds the necessary installer classes to your project as part of a separate module.
This includes two classes: System.ServiceProcess.ServiceProcessInstaller and System.ServiceProcess.ServiceInstaller. Several properties may be set using the Properties window of each class. The most important property is Account within the ServiceProcessInstaller class. It specifies the Windows account under which the service runs (security context). The following options are available:
When an installer is added to the Service, the ProjectInstaller class is added. Defining properties via each class's Properties window results in an associated line of code in the corresponding ProjectInstaller class. The following code shows a sample installer for our C#-based Windows service with various properties defined, including the Account set to LocalService and ServiceName set to BuilderService.
using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
namespace WindowsService1 {
[RunInstaller(true)]
public class ProjectInstaller :
System.Configuration.Install.Installer {
public System.ServiceProcess.ServiceProcessInstaller
serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller
testInstaller;
private System.ComponentModel.Container components = null;
public ProjectInstaller() {
InitializeComponent();
}
protected override void Dispose( bool disposing ) {
if(disposing) {
if(components != null) {
components.Dispose();
} }
base.Dispose( disposing );
}
#region Component Designer generated code
private void InitializeComponent() {
this.serviceProcessInstaller1 = new
System.ServiceProcess.ServiceProcessInstaller();
this.testInstaller = new
System.ServiceProcess.ServiceInstaller();
this.serviceProcessInstaller1.Account =
System.ServiceProcess.ServiceAccount.LocalService;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
this.testInstaller.DisplayName = "Test Installer";
this.testInstaller.ServiceName = "BuilderService";
this.testInstaller.StartType =
System.ServiceProcess.ServiceStartMode.Automatic;
this.Installers.AddRange(
new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.testInstaller});
}
#endregion
} }
The corresponding VB.NET code follows:
Imports System.ComponentModel
Imports System.Configuration.Install
<RunInstaller(True)> Public Class ProjectInstaller
Inherits System.Configuration.Install.Installer
#Region " Component Designer generated code "
Public Sub New()
MyBase.New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
Private components As System.ComponentModel.IContainer
Public WithEvents ServiceProcessInstaller1 As
System.ServiceProcess.ServiceProcessInstaller
Public WithEvents ServiceInstaller1 As
System.ServiceProcess.ServiceInstaller
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.ServiceProcessInstaller1 = New
System.ServiceProcess.ServiceProcessInstaller
Me.ServiceInstaller1 = New
System.ServiceProcess.ServiceInstaller
Me.ServiceProcessInstaller1.Account =
System.ServiceProcess.ServiceAccount.LocalService
Me.ServiceProcessInstaller1.Password = Nothing
Me.ServiceProcessInstaller1.Username = Nothing
Me.ServiceInstaller1.DisplayName = "Test Service"
Me.ServiceInstaller1.ServiceName = "BuilderService"
Me.ServiceInstaller1.StartType =
System.ServiceProcess.ServiceStartMode.Automatic
Me.Installers.AddRange(New
System.Configuration.Install.Installer()
{Me.ServiceProcessInstaller1, Me.ServiceInstaller1})
End Sub
#End Region
End Class
With the installers added to the project, you may now install the Windows Service and run it on the target computer. Another approach within our project is how the service is started. There are three options:
In our example, I have the Service start automatically. With the Service properly compiled, we install it on the target computer via the Microsoft .NET Framework Installation utility (InstallUtil.exe) command-line tool. It allows you to easily install and uninstall our service. The compiled file (executable) or assembly is passed to it. Also, it provides the following command-line switches:
With our sample Service, the following line takes care of the installation:
InstallUtil WindowsService.exe
The line is run in the directory containing the assembly; otherwise, it would require the complete path to the assembly. After you install the new Service, it's located in the Services window of the Computer Management applet.
Triggering execution
Once you properly install the Service, it's triggered based upon the Service setting. Unfortunately, it's only executed when loaded or run by a user. You may augment this by adding a timer to the code, so the agent executes on a scheduled basis. The next VB.NET code listing shows our Service with a Timer object added. The timer is started when the Service starts, and it stops when the Service stops.
Imports System.Diagnostics
Imports System.ServiceProcess
Imports System.Timers
Public Class Service1
Inherits System.ServiceProcess.ServiceBase
Private log As EventLog
Private t As Timer
Public Sub New()
MyBase.New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
log.WriteEntry("Service dispose",
EventLogEntryType.Information)
log.Close()
MyBase.Dispose(disposing)
End Sub
<MTAThread()> _
Shared Sub Main()
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
ServicesToRun = New System.ServiceProcess.ServiceBase() {New
Service1}
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
End Sub
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
components = New System.ComponentModel.Container
Me.ServiceName = "Service1"
End Sub
Protected Overrides Sub OnStart(ByVal args() As String)
log = New EventLog("Builder.com")
log.WriteEntry("Service Starting",
EventLogEntryType.Information)
t = New Timer(3600000)
AddHandler t.Elapsed, AddressOf TimerFired
With t
.AutoReset = True
.Enabled = True
.Start()
End With
End Sub
Protected Overrides Sub OnStop()
log.WriteEntry("Service Stopping",
EventLogEntryType.Information)
t.Stop()
t.Dispose()
End Sub
Private Sub TimerFired(ByVal sender As Object, ByVal e As
ElapsedEventArgs)
' Deal with firing
End Sub
End Class.
Use the right tool
A Windows Service is an excellent application choice when working with administrative tasks or automating routine tasks. Add it to your toolbox and use it when the situation arises.
TechRepublic's free .NET newsletter, delivered each Wednesday, contains useful tips and coding examples on topics such as Web services, ASP.NET, ADO.NET, and Visual Studio .NET. Automatically sign up today!
Print/View all Posts Comments on this article
|
|
|
|
|
|
White Papers, Webcasts, and Downloads
- Five Steps to Determine When to Virtualize YourServers VMware Thinking of virtualizing the servers at your company? Use this step-by-step guide to determine when's the best time to make your big move. Download Now
- Dell Helps Medical University of South Carolina Bring the Intelligent Classroom to Life Dell Established in 1824, Medical University of South Carolina (MUSC) is one of ... Download Now
- Building the Virtualized Enterprise with VMware Iinfrastructure VMware VMware virtualization software has been adopted by over 120,000 enterprise ... Download Now
- The Impact of Virtualization Software on Operating Environments VMware Today's use of virtualization technology allows IT professionals to ... Download Now
- Dell IT Cuts Energy Costs by Up to 40 Percent With a New Power Management Plan Dell Energy conservation is an increasingly important issue for organizations ... Download Now
Article Categories
- Security
- Security Solutions, IT Locksmith
- Networking and Communications
- E-mail Administration NetNote, Cisco Routers and Switches
- CIO and IT Management
- Project Management, CIO Issues, Strategies that Scale
- Desktops, Laptops & OS
- Windows 2000 Professional, Microsoft Word, Microsoft Excel, Microsoft Access, Windows XP,
- Data Management
- Oracle, SQL Server
- Servers
- Windows NT, Linux NetNote, Windows Server 2003
- Career Development
- Geek Trivia
- Software/Web Development
- Web Development Zone, Visual Basic, .NET

