翻译
Mark Strawmyer 著 Creating a Windows Service in .NET (developer.com)
flanker 翻译 in MSProject
简介
在本文中我们将探讨如何创建一个Windows服务的应用程序。我将说明什么是Windows服务,以及如何创建、安装和调试它。这需要使用System.ServiceProcess.ServiceBase命名空间中的类。
什么是Windows服务?
Windows服务应用程序是在服务器环境中长期运行的应用程序,它没有界面或者可视化的输出,信息一般都写入事件日志中。服务可以在操作系统启动时自动的开始运行,而不需要用户登录来运行它,并且服务可以运行在任何用户的账户中包括system账户。Windows服务通过Service Control Manager(SCM服务控制程序)来管理,控制服务的停止、暂停和重启等。
Windows服务,之前称为NT服务,是在Windows NT操作系统引入的,所以它不适用于Windows 9X或Windows ME系统。要运行Windows服务,你需要NT系列的操作系统,比如Windows NT、Windows 2000等。举几个例子,Microsoft Exchange、SQL Server就是服务器程序的Windows服务,而设置计算机时间的Windows Time是应用程序的Windows服务。
创建一个Windows服务
下面我们创建一个示例,它并没有什么实际用途。当服务启动后,它将在数据库中记录一个表示启动的条目。在它运行期间,每隔特定时长就在数据库中记录一个条目。当它停止时,它会记录一个终止的条目。这个服务也会在启动或者停止成功时,记录在Windows事件日志中。
在Visual Studio .NET中建立Windows服务相对的很简单。下面列出了创建这个示例的步骤:
1. 新建一个项目
2. 在模板中选择Windows服务
3. 设计器将会打开设计模式
4. 从工具箱的组件项里拖拉一个Timer对象到设计器上(注意:使用组件项里的Timer,而不是Windows窗体里的)
(flanker注:这里是指需要System.Timers.Timer,而不能使用System.Windows.Forms.Timer。在我的VS2005中,System.Timers.Timer并没有默认出现在工具箱里,需要自己手工添加。)
5. 在Timer属性里将Enabled设置为false,将Interval设置为30000毫秒
6. 切换到代码模式(F7),给服务增加功能
Windows服务的组成
通过代码你会发现Windows服务是继承于System.ServiceProcess.Service类,所有.NET建立的Windows服务都必须继承自这个类。你需要重写以下几个Visual Studio默认提供的方法:
OnStart - 控制服务启动
OnStop - 控制服务终止
Dispose - 清理所有托管和非托管的资源
示例数据库的脚本
下面的T-SQL脚本用来在示例中创建数据库的表。我使用的是SQL Server,你也可以使用Access或者别的选择。
CREATE TABLE [dbo].[MyServiceLog] (
[in_LogId] [int] IDENTITY (1, 1) NOT NULL,
[vc_Status] [nvarchar] (40)
COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[dt_Created] [datetime] NOT NULL
) ON [PRIMARY]
示例windows服务
下面是名为MyService的Windows服务示例源代码,代码的大部分都是Visual Studio自动生成的。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.ServiceProcess;
namespace CodeGuru.MyWindowsService
{
public class MyService : System.ServiceProcess.ServiceBase
{
private System.Timers.Timer timer1;
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
public MyService()
{
// This call is required by the Windows.Forms
// Component Designer.
InitializeComponent();
}
// The main entry point for the process
static void Main()
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[]
{ new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.timer1 = new System.Timers.Timer();
((System.ComponentModel.ISupportInitialize)
(this.timer1)).BeginInit();
//
// timer1
//
this.timer1.Interval = 30000;
this.timer1.Elapsed +=
new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
//
// MyService
//
this.ServiceName = "My Sample Service";
((System.ComponentModel.ISupportInitialize)
(this.timer1)).EndInit();
}
///
/// Clean up any resources being used.
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
///
/// Set things in motion so your service can do its work.
///
protected override void OnStart(string[] args)
{
this.timer1.Enabled = true;
this.LogMessage("Service Started");
}
///
/// Stop this service.
///
protected override void OnStop()
{
this.timer1.Enabled = false;
this.LogMessage("Service Stopped");
}
/*
* Respond to the Elapsed event of the timer control
*/
private void timer1_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
this.LogMessage("Service Running");
}
/*
* Log specified message to database
*/
private void LogMessage(string Message)
{
SqlConnection connection = null;
SqlCommand command = null;
try
{
connection = new SqlConnection(
"Server=localhost;Database=SampleDatabase;Integrated
Security=false;User Id=sa;Password=;");
command = new SqlCommand(
"INSERT INTO MyServiceLog (vc_Status, dt_Created)
VALUES ('" + Message + "',getdate())", connection);
connection.Open();
int numrows = command.ExecuteNonQuery();
}
catch( Exception ex )
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
command.Dispose();
connection.Dispose();
}
}
}
}
安装Windows服务
Windows服务有别于其他普通Windows应用程序,不能简单的运行一个EXE文件来启动它。Windows服务应该使用.NET Framework提供的InstallUtil.exe程序来安装,或者通过一个部署项目,比如Microsoft Installer(MSI)文件。
添加安装程序
仅仅创建了Windows服务还不能用InstallUtil程序来安装它。你必须给你的Windows服务添加一个安装程序,这样InstallUtil或者其他的工具才能知道服务的具体配置。
1. 切换到服务的设计模式
2. 右键单击,选择添加安装程序
3. 切换到新增的ProjectInstaller的设计模式
4. 设置serviceInstaller1组件的属性:
ServiceName = My Sample Service
StartType = Automatic
5. 设置serviceProcessInstaller1组件的属性:
Account = LocalSystem
6. 生成解决方案
以上几步完成后,Visual Studio会在ProjectInstalle.cs源文件中自动生成如下的代码。
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
namespace CodeGuru.MyWindowsService
{
///
/// Summary description for ProjectInstaller.
///
[RunInstaller(true)]
public class ProjectInstaller :
System.Configuration.Install.Installer
{
private System.ServiceProcess.ServiceProcessInstaller
serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller serviceInstaller1;
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
public ProjectInstaller()
{
// This call is required by the Designer.
InitializeComponent();
// TODO: Add any initialization after the InitComponent call
}
Component Designer generated code
}