网站首页/技术开发列表/内容

创建一个Windows Service应用程序

技术开发2022-07-12阅读
创建一个Windows Service应用程序
--------------------------------------------------------------------------------


下载本文代码
见资源

正是由于.NET Framework的出现,才使你能够构建出在系统重新启动时自动运行的、无人参与的(unattended)应用程序。
by Stan Schultes
技术工具箱:VB.NET, XML, ASP
Windows service应用程序曾经是C++程序员专用的领域,除非你在VB中使用了第三方工具。现在它们则成为System.ServiceProcess 命名空间下的.NET Framework类库中的主要部分,你可以随意使用任何.NET语言来构建它。Windows service是一种系统自动的、无人参与的程序(仅存在于Windows NT、2000和XP操作系统中),它能够在系统启动时开始运行。你可以通过Service Control Manager (SCM) applet或者一些特殊的service-control应用(utility)来访问Windows service。

我将讲解如何构建一个用于监控文件改变情况的Windows service。FileChangeMonitor service用于随意地编写事务日志(event-log)条目以及当文件在一段时间内没有改变时发送e-mail。这种文件监控过程在用于确保需要时进行备份、正常运转报告生成器或按时间表将文件传送到远程系统上时是非常有用的。FileChangeMonitor service还能够发送显示程序正常运行的综合报告。

第一步是构建一个作为将来service项目起始点的Windows service程序的模板。打开Visual Studio.NET,用Windows Service模板来创建一个新的项目,将其命名为FileChangeMonitor(点此下载范例代码)。鼠标右键单击Solution Explorer(SE)中的Service1.vb文件并将其重新命名为ChangeMonitor.vb。点击ChangeMonitor 设计界面(你会看到“To add components to your class”消息),并将其在属性窗口(按F4显示的窗口)中的的名字和ServiceName属性均改为ChangeMonitor。

同样将属性窗口中的CanPauseAndContinue和CanShutdown属性值设置为True。 这些属性控制着该service程序是否能够暂停/继续,以及在系统关闭时是否做出响应。你将在后面使用这些事件(以及Stop事件)来保存你的service的“状态”――即给定时间内的执行文本(execution context )。

接下来,点击ChangeMonitor 设计窗口中的“click here to switch to code view”链接。在代码窗口中,点击左边的加号来打开名为“Component Designer generated code”的区域。在Sub Main过程(routine)中,将ServicesToRun 赋值语句中的Service1改为ChangeMonitor: ServicesToRun = New System. _
 ServiceProcess.ServiceBase() _
 {New ChangeMonitor()}





右键单击在SE中的FileChangeMonitor项目,选中属性,再从StartupObject下拉列表中选择Sub Main。现在你就可以开始构建你的项目了(通过使用Build | Build Solution菜单项)。

创建事件模板和过程
现在,在模板中加入一些事件过程(event-routine)的原型。你等一会儿可以将代码添加到这些service事件中去以便处理 Windows service程序中的状态变化。在代码窗口中点击Class Name combo box(位于代码窗口上面左侧的combo box),然后选中(Overrides)选项。在Method Name combo box中(位于代码窗口上面右侧的combo box),依次选中各项以便将过程原型(一个空程序)添加到代码窗口中,比如:OnContinue、OnPause和OnShutdown。你必须在每个过程中的Method Name combo box中重新选择(Overrides)选项 。

接下来就开始构建过程模板。在你需要添加代码的ChangeMonitor.vb中创建五个子过程原型: LoadSettings()、SaveSettings()、RunCheck()、RunSummary()和StartService()。在这个类的最顶部Imports System.ServiceProcess语句的下面,通过使用Imports语句来添加其他需要用到的命名空间:Imports System.IO
Imports System.Timers
Imports System.Web.Mail
Imports System.Reflection
Imports System.Xml.Serialization





由于你的service应用程序不是一个Web项目,因此你可能需要手动将一个引用(reference)添加到Web.Mail命名空间下。右键单击SE中的FileChangeMonitor项目,从弹出菜单中选择Add Reference。在 Add Reference对话框中选择列表中的System.Web.dll条目,单击Select按钮,然后点OK。

在ChangeMonitor类的顶部、Component Designer区域的前面,添加一个用于文件检查功能的Timer对象的声明: Private WithEvents ControlTimer As Timer



然后将下面三行代码加到OnStart和OnContinue事件程序中: StartService()
RunCheck()
RunSummary()





当你的service启动时会触发OnStart事件,而当暂停后继续运行时则会触发OnContinue事件。

在Class Name combo box中选择ControlTimer,并在Method Name combo box中选择Elapsed。这样就会将ControlTimer_Elapsed事件过程原型添加到项目中了。只需添加这两个Run语句到ControlTimer_Elapsed事件过程中,然后在OnPause、OnShutdown和OnStop事件过程中添加代码来中断计时器(Timer)并保存设置: ControlTimer.Stop()
SaveSettings()





从这个简单的程序大纲中你可以看到用于Windows service应用程序的文件检查功能的控制流程是如何运作的。当其中一个事件触发时,StartService函数便会加载设置,然后运行文件和简要检查。你可以在计时器时间到时运行检查程序;可以用stop或pause事件来中断计时器以及保存设置。

在StartService过程中添加代码来创建计时器,将时间间隔定为15秒(以毫秒值计),然后启动它:ControlTimer = New Timer()
ControlTimer.Interval = 15000
ControlTimer.AutoReset = True
ControlTimer.Start()





AutoReset = True属性设定使计时器在时间到时继续运行。接下来,你可以在check函数运行时添加代码来编写Windows Application事务日志,这样你就可以看到service正在运行: Private Sub RunCheck()
 EventLog.WriteEntry(ServiceName & _
" - Check", "Checking Files.")
End Sub





你可以通过Windows中的Event Viewer(EV)应用程序来查看事件日志中的消息。

添加一个安装程序(Installer)
创建service应用程序模板的最后一项工作是在项目中添加一个安装程序。在它运行之前你需要首先注册这个Windows service程序。切换到ChangeMonitor设计界面并打开属性窗口(如果看不到的话可以按F4),你可以看到在属性窗口下面有一个名为Add Installer的链接,点击该链接后会出现一个向导来引导你将一个名为ProjectInstaller的组件添加到当前项目中。这个向导在ProjectInstaller设计界面中放置了两个service控件:ServiceProcessInstaller和ServiceInstaller。


图1. 设置Service属性
点击ServiceProcessInstaller控件并对Account属性进行设置。你可能希望选择LocalSystem(大多数service是运行在LocalSystem中的),但如果你喜欢,你还可以将它设置为一个用户帐户。点击ServiceInstaller,将它的属性设置为DisplayName = FileChangeMonitor、 ServiceName = ChangeMonitor以及StartType = Automatic(如果你希望通过手动启动该service的话也可以将它设置为Manual)。

通过Build | Build Solution来构建你自己的项目,确保不存在什么错误。现在你就可以使用一个名为InstallUtil的Framework应用来安装你的service了。打开命令行提示(command-prompt)窗口并执行corvars.bat文件来设置环境变量(你可以下载readme文件来了解详细内容)。使用cd(change directory)命令将其导航到你项目中的\bin目录下。执行以下命令来安装你的service:> InstallUtil filechangemonitor.exe




现在你可以使用Control Panel的Administrative Tools菜单(Win2K 和WinXP操作系统)中的SCM applet来启动、停止、暂停以及继续运行你的FileChangeMonitor service了 (见图1)。当你启动这个service后就可以使用EV来查看Application事务日志中由该service生成的事件了。点击F5刷新EV的显示,你会看到“Check messages every 15 seconds”。你可以使用以下命令来卸载这个service(先用SCM来终止service): > InstallUtil filechangemonitor.exe /u




现在你可以保存该项目并将它作为以后service程序的一个模板。

Service以某种状态运行(这可能是它未运行时保存的一组设定)。当service重新启动时,你可以加载它上次运行时的状态。一个简便的方法是使用.NET Framework中的序列化类(serialization class),如System.Xml.Serialization命名空间下的XML序列化(你也可以选择binary和SOAP序列化)。

用XML序列化保存设置
XML序列化是和用<Serializable()>属性标记的类配合使用的。右键单击SE中的FileChangeMonitor项目,从弹出的菜单中选择Add | Add Class,将该类命名为CMonitor并点击 OK。在CMonitor中添加两个类――MonitorHeader和MonitorFile: <Serializable()> Public Class MonitorHeader
 Public MonitorIntSecs As Integer
 '<other header properties>
 Public Files() As MonitorFile
End Class
<Serializable()> Public Class MonitorFile
 Public Path As String
 '<other file properties>
End Class




MonitorHeader包含控制service的设置,包括一组MonitorFile对象。MonitorFile对象中包含每个你想要检查进度的文件的监控设置。你可以将大多数类的属性当作Public变量来实现,因为它们只用于你的service项目中。查看范例代码来了解该类的完整定义。你可以在ChangeMonitor 类的模块中实现LoadSettings和SaveSettings序列化过程(见列表1)。

在用于声明设置对象和存储设置文件路径的ChangeMonitor类的顶部添加该类的私有变量:Private m_MonitorControl As New _
 MonitorHeader()
Private m_sSettingsPath As String




在调用StartService()之前将代码添加到OnStart过程中,来完成在service启动之前对设置文件名进行检测。用Reflection来找到应用程序的runtime .exe路径,并用substitute .xml作为文件的扩展名(这两个文件在同一目录下): m_sSettingsPath = [Assembly]. _
 GetEntryAssembly.Location. _
 Replace(".exe", ".xml")





在VB.NET中assembly是一个关键字,因此在代码中你必须把它用一个方括号括起来。你需要整理StartService()过程以便从设置文件中加载计时器间隔: If m_MonitorControl _
 .MonitorIntervalSecs > 0 Then
 ControlTimer.Interval = _
Ctype(m_MonitorControl _
.MonitorIntervalSecs * 1000, Double)
 ControlTimer.AutoReset = True
 ControlTimer.Start()
End If




现在,你可以实现主要的检查函数――RunCheck了(见列表2)。RunCheck负责调用RunAlarmAction并计算出Files数组中每个文件的出现次数,该文件的NextCheck代表的是当前时间之前的时间并且自从上次检查以后就没有发生过改变。RunAlarmAction负责检查AlarmAction标记、编写事务日志,然后通过SendEmail过程来发送e-mail (见列表3)。

你可以采用类似的方法,基于MonitorHeader结构的汇总设置(summary setting)来实现RunSummary和RunSummaryAction方法,构建并测试你的Windows service应用程序。范例代码中还包括一个名为FileChgCtl的service-control应用。它主要用于调试目的,可以将自定义命令(custom command)发送到FileChangeMonitor service中。自定义命令是一个范围在128到255之间的整数。当Windows service应用程序中的OnCustomCommand事件触发时你会得到自定义命令出现的通知。

你会发现service 应用程序在很多情况下是非常有用的,比如用在系统维护、监控以及其他自动的、无人照顾的操作中。Windows service通常会通过事务日志来记录其活动情况,但正如我所介绍的,你的service也可以通过发送e-mail来方便地跟踪其进展情况。构建Windows service应用程序的能力使你在用Windows构建有效的商务方案方面得以轻松地扩展。


关于作者:
Stan Schultes 是Florida州Sarasota地区的一名Web和企业应用程序的架构师和开发人员,以及VB开发领域的MCP。Stan是VSM的一名特约编辑,定期为该杂志撰写文章。你可以访问Stan的网站www.vbnetexpert.com查看在线代码演示、更新资料以及其他信息。他的e-mail地址是stan@vbnetexpert.com。

……

相关阅读