flanker base @ cnblogs

defy all challenges & accelerate your life

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

翻译

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 (11NOT 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;
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
  }

}

使用InstallUtil安装Windows服务

现在你需要安装你的服务了。按照如下步骤提示,安装你的服务。

1. 打开Visual Studio命令提示
2. 切换到你的项目路径中的bin\Debug目录(如果你用Release模式编译,则进入bin\Release目录)
3. 输入 InstallUtil MyService.exe 来注册你的服务,它将添加所需的注册表信息。
4. 在桌面我的电脑右键选择管理,打开计算机管理
5. 在服务与应用程序中选择服务,你就可以在列表中看到你的服务
6. 右键点击你的服务,选择启动

任何时候你如果需要改变你的Windows服务,你都需要卸载并重新安装它。在卸载服务前,你最后先关闭了服务管理控制台,否则可能在卸载中遇到问题。要卸载服务,只需输入和注册时一样的命令,只不过在后面加上一个/u开关。

调试Windows服务

调试Windows服务比普通应用程序要困难些,需要很多步骤。服务不能像普通应用程序那样在开发环境中直接执行来调试,它必须先安装并启动。一旦启动了它,你可以用Visual Studio附加到进程来调试代码。记住,对Windows服务做的任何改动,你都需要卸载并重新安装它。

附加到运行的Windows服务

要调试服务,你需要按如下步骤附加到Windows服务。这里假设你已经安装了服务并成功启动了它。

1. 在Visual Studio中打开项目
2. 选择调试
3. 选择附加到进程
4. 打开选择所有用户的进程
5. 在可用进程中选择你的进程
6. 点击附加
7. 在timer1_Elapsed方法里设置一个断点,等待它的执行

总结

现在你已经大概了解了什么是Windows服务,以及如何创建、安装和调试它。Windows服务还有许多功能需要你去学习,比如暂停(OnPause)和恢复(OnContinue)等。这几个属性在默认中没有给出,但你可以在属性面板里面设置。

关于作者

Mark Strawmyer, MCSD, MCSE (NT4/W2K), MCDBA 是.NET应用程序高级架构师,服务于大中型组织。Mark是印第安纳波利斯Crowe Chizek公司的技术领导,他关注于架构、设计和开发基于微软技术的解决方案。

附件代码

flanker注:原文并没有附带源代码,因为代码比较简单。这是我自己按照文章做的项目文件。有一点不同:原文输出到数据库,比较麻烦,我这里改用了一个Log类,输出到了文本文件。大家可以看看。
MyService.zip

 

posted on 2007-12-30 04:38  flankerfc  阅读(692)  评论(2编辑  收藏  举报