搜档网
当前位置:搜档网 › C#发现之旅 --- C#开发Windows Service程序

C#发现之旅 --- C#开发Windows Service程序

C#发现之旅C#开发Windows Service程序

本课程介绍

本课程说明了Windows Service程序的概念,并演示如何使用C#开发一个简单的Windows Service程序。C#工程名为MyWindowsService,编译生成的文件是MyWindowsService.exe。本课程的演示代码下载地址为

https://www.sodocs.net/doc/1e18063899.html,/xdesigner/MyWindowsService.zip。

Windows Service概念介绍

Windows Service,也称Windows服务,是32位Windows操作系统中一种长期运行的后台程序。它们长期后台运行,没有用户界面,默默无闻,但它们却是支持Windows正常运行的幕后英雄,却永无出头之日。

Windows服务程序为其他系统模块提供了非常重要的服务,而且各个Windows 服务分工明确,比如IISAdmin服务提供WEB内容的发布功能,若IISAdmin服务不启动,则静态HTML页面、ASP、https://www.sodocs.net/doc/1e18063899.html,或者WebService等等统统不行;有个名为“Print Spooler”的服务用于提供打印支持,若该服务不启动,则任何软件都不能进行打印,比如Word,记事本或者报表软件等等。

Windows启动后在没有用户登录时就会启动Windows服务。Windows NT和Windows2000,以及更新的版本操作系统能运行Windows服务,但Windows98及其前期版本是不能运行服务的。

我们打开Windows资源管理器,在左边的树状列表中选中“桌面-控制面板-管理工具”。

在右边的列表中打开“服务”项目即可打开Windows服务管理器。

在这些服务中,有我们最熟悉的IIS Admin和World Wide Web Publishing服务了。我们双击一个服务项目即可打开服务属性对话框。

Windows服务有一个服务名称属性,该属性是服务的惟一的不可重复的名称,我们可以在命令行中使用命令“net start 服务名称”来启动服务,使用“net stop 服务名称”来停止服务。

Windows服务的启动类型有自动,手动和已禁用。当启动类型为自动时,Windows 启动后不等用户登录就自动启动服务,当启动类型为手动时,需要某个操作员登录后点击这里的“启动”按钮来启动服务,而当启动类型为已禁用时,Windows服务不能启动。

该页面中的“启动”按钮用于启动尚未启动的Windows服务,运行提供服务的进程;“停止”按钮用于停止已经启动的服务,杀死服务进程;而“暂停”按钮用于通知服务进程暂时停止提供服务,但服务进程依然存在;而“恢复”按钮用于通知处于暂停模式的服务进程重新提供服务。

我们可以查看服务属性对话框的“登录”页面。

可以指定服务使用本地系统帐户登录,也可另外指定其他的用户,这里有一个允许服务和桌面交互的选项,若选中此选项,则Windows服务可以显示图形化用户界面,比如显示自己的窗体,显示消息框等等。不过不建议使用该选项,而且Windows服务运行时不要显示图形化用户界面。

我们切换到“依存关系”页面,可以看到本服务和其他服务的依存关系。

各个Windows服务之间可能存在依赖关系,比如IISADMIN服务就依赖另外一个名为RPC的Windows服务,当启动一个Windows服务时,系统会启动该服务所依赖的其他Windows服务。例如我们设置IISADMIN服务为自动启动,而RPC服务为手动启动,则Windows启动后会试图自动启动IISADMIN服务,结果会首先启动RPC服务,即使RPC服务不是自动启动。若RPC服务为禁止,无论如何也不能启动,则IISADMIN服务就无法自动启动了。

C#编写Windows服务的基本过程

编写Windows服务是一种比较高级的编程技术,内部使用了很多Windows操作系统的核心功能,但微软.NET框架已经很好的封装了这些技术细节,使得我们可以很方便的使用C#编写自己的Windows服务,其基本过程一般为

1.创建C#工程。创建一个EXE工程,可以是

WinForm或者命令行格式的。添加对

System.ServiceProcess.dll和

System.Configuration.Install.dll的引用。

2.创建服务类。新增一个类,该类型继承

System.ServiceProcess.ServiceBase类型,在构造函数中设置ServiceName属性来指明该服务的名称。然后重载它的OnStart方法来响应启动服务的事件,重载OnStop方法来响应停止服务的事件,重载OnPause方法来响应暂停服务的事件,重载OnContinue方法来响应恢复提供服务的事件。

在重载这些方法时必须要立即返回,其中不能出现长时间的操作,若处理时间过长则Windows服务管理器会觉得该Windows服务停止响应而报错。为此我们可以使用一个线程来进行实际的工作,而

OnStart方法创建线程,OnStop方法关闭线程,OnPause方法挂起线程,而OnContinue方法来恢复运行线程。

3.启动服务。在main函数中调用

“System.ServiceProcess.ServiceBase.Run( 自定义服务类的实例 )”来运行服务。比如

“System.ServiceProcess.ServiceBase.Run( new MyService() )”,这里的MyService就是继承自ServiceBase。

4.安装服务。新增一个类,该类型继承自

System.Configuration.Install.Installer类型,该类型用于配合微软.NET框架自带的安装命令行

工具InstallUtil.exe的。我们为该类型附加

https://www.sodocs.net/doc/1e18063899.html,ponentModel.RunInstallerAttrib ute特性,并在它的构造函数中使用

System.ServiceProcess.ServiceInstaller对象和

System.ServiceProcess.ServiceProcessInstal

ler对象向系统提供该服务的安装信息。程序编译后

我们可以使用命令行“InstallUtil.exe EXE文件

名”向Windows服务管理器注册服务,可以使用命

令行“InstallUtil.exe /u EXE文件名”从Windows

服务管理器中注销服务。

5.编写服务客户端。这是一个根据实际情况而可选的

过程,由于Windows服务是没有用户界面的,因此

我们可以编写一个具有用户界面的程序来显示和控

制Windows服务提供的数据,并进行一些系统设置

等操作。比如对于MS SQL Server,数据库引擎是

以服务的形式存在,而SQL Server企业管理器就

是一个客户端软件。

软件功能需求

现在我们要求使用C#和https://www.sodocs.net/doc/1e18063899.html,2005开发一个软件,该软件功能为

1.该软件能监视指定目录下的文件和子目录的新增,

修改,删除和重命名操作,并将操作日志记录到一

个数据库中。

2.该软件以Windows服务的形式运行,能监视不同

的用户帐户的操作记录。

3.有一个客户端软件能控制服务,并能查看服务的保

存的监视记录。其用户界面为

客户端软件还能设置服务监视的目录,系统设置对话框为

软件设计

一般而言,我们将服务和客户端分成两个C#工程开发,但这里为了方便我们只在一个工程中实现服务器和客户端软件的开发。Windows服务是不能显示图形化用户界面的,但并不是说Windows服务的软件中不能包含显示图形化用户界面的软件模块。我们完全可以编写一个EXE,其中包含服务器和客户端两个相互独立的软件模块。直接执行EXE将以服务模式运行,若带有命令行参数将以客户端模式运行。为此我们设计了如下的命令行参数

使用https://www.sodocs.net/doc/1e18063899.html,调试服务是一个比较麻烦的事,首先我们得安装并运行服务,然后使用https://www.sodocs.net/doc/1e18063899.html,的菜单项目“工具-附加到进程”的操作来附加到服务程序,然后设置断点进行调试,其中OnStart函数是没有办法设置断点调试的。为此我们专门添加一个“/debug”命令行参数使得程序不进入服务模式,而是直接运行提供服务内容的功能性代码,然后主线程休眠,但功能性代码还在运行,可以调试。这样我们在https://www.sodocs.net/doc/1e18063899.html,

中设置断点后可以直接运行进行调试了。

这里我们设计的C#工程名称为MyWindowsService,编译生成的文件为MyWindowsService.exe。

在本软件中,数据将保存到应用程序目录下的一个名为FileSystemWatcher.mdb 的Access2000格式的数据库。数据库中的表结构为

文件系统操作日志表 FileSystemLog,字段有

该数据表中保存的数据范例为

对于新增文件或目录操作其EventStyle 值为Created ,对于修改为

Changed ,对于删除为Deleted ,对于重命名为Renamed 。

系统设置信息表 SystemConfig ,字段有

该数据表中保存的数据的范例为

在这里配置项LogChanged表示是否监视文件内容是否被改变事件,配置项LogCreated表示是否监视新建文件或目录事件,配置项LogDeleted表示是否监视文件或目录删除事件,配置项LogRenamed表示是否监视文件或目录重命名事件。而path0,path1,path2等表示监视的路径,支持通配符。系统配置中可以有若干个path配置项。

我们可以使用System.IO.FileSystemWatcher来监视文件系统的对象的修改,我们可以使用它的Path属性来设置要监视的文件夹,使用Filter属性来设置文件名过滤器,然后响应它的Changed事件来处理文件内容修改操作,响应Created事件来处理新增文件或目录操作,响应Deleted事件来处理删除文件或目录操作,响应Renamed事件来处理文件和目录重命名操作。这这里我们简单是将这些事件信息保存到数据表FileSystemLog中。程序在监视文件系统前会读取系统配置信息表SystemConfig中读取配置信息,根据其中的path配置项目创建若干个FileSystemWatcher对象展开监视。

我们选定服务的名称为“MyFileSystemWatcher”。

本软件的客户端具有一个图形化用户界面,其界面设计如下

此外还有一个系统配置对话框,用于查看和修改数据表SystemConfig中保存的系统配置信息。

软件说明

根据上述的软件设计,我已经把软件编写完毕,现对该软件结构进行说明

本软件为一个C#编写的EXE,主要包含服务端软件模块和客户端软件模块。首先对比较好理解的具有图形化用户界面的客户端模块进行说明,客户端的主界面为

这个界面主要功能是数据库信息管理,最上面为一个工具条,中间大部分的一个ListView控件,最下面为状态栏。

对于ListView控件其内容是分组的,因此需要设计其分组信息,在https://www.sodocs.net/doc/1e18063899.html,的窗体设计器中我们点中ListView控件,在旁边的属性列表中选择Groups属性,点击旁边的小按钮可以弹出分组设计器。

使用这个分组编辑器我们可以很容易的设计该ListView控件的分组信息。

这个窗体的加载事件处理为

在这里我们首先创建一个联系到文件监视服务的ServiceController,调用它的Status属性,若一切正常则表示服务已经安装,我们设置bolServiceInstalled的标志变量,若发生错误则服务尚未安装,则显示“服务尚未安装”的提示信息。

对于工具条的“刷新列表”按钮,其点击事件处理为

在该按钮事件处理中,我们查询数据表FileSystemLog,对每一条查询所得的数据创建一个ListViewItem项目,并根据记录的EventStyle值设置该列表项目的图标序号和分组状态。

工具条的“删除记录”按钮用于删除列表中选择的项目,其点击事件处理为

相关主题