分享
 
 
 

编写 Window 服务程序

王朝c#·作者佚名  2006-12-17
窄屏简体版  字體: |||超大  

编写 Window 服务程序 一、直观认识Windows服务。 打开Windows“控制面板/管理工具/服务”,系统显示Windows服务列表。

双击服务,可以显示和更改服务属性。在这个对话框中,可以控制服务的启动、暂停和停止。在这里还可以配置服务的启动类型,令服务在系统启动时自行启动。因此,Windows服务经常作为服务器程序运行。
在故障恢复这个属性页,可以配置该服务失败后系统的相应。一些病毒程序就是在这里做文章,将病毒程序激活的。
二、Windows服务的开发要点 Visual Studio的随机文档里,详细介绍了Windows服务程序的开发步骤,并且带有实例,笔者不再赘述。读者只需注意几个要点: 1、创建一个派生自ServiceBase的入口类。这个入口类管理这个Windows服务的生存期。 public class MyService : System.ServiceProcess.ServiceBase { …… } 2、在入口类的main方法里将服务向Windows的服务控制器(Service Control Manager, SCM)注册,代码: …… System.ServiceProcess.ServiceBase[] ServicesToRun; ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MyService() }; System.ServiceProcess.ServiceBase.Run(ServicesToRun); …… 3、重写 OnStart 、OnStop ,或OnPause 和 OnContinue 方法来响应服务状态的更改。通常需要重写 OnStart 方法,结束服务时在 OnStop 方法中释放资源,酌情重写OnPause 和 OnContinue方法。 4、Windows服务通常启动一个定时器来定时或轮询进行业务处理。 5、Windows服务需要安装后才能使用。通常通过两个办法安装Windows服务:在命令行运行InstallUtil.exe;在Windows服务程序的代码中添加ProjectInstraller类的实例,里面包含ServiceProcessInstaller类和ServiceInstaller类的实例。 上述两个办法在Framework的随机文档中均有描述,在此不再赘述。 6、Windows服务在Windows的服务控制器(Service Control Manager, SCM)中运行,因此调试起来不像其他Visual Studio应用程序那样简单。关于Windows服务的调试,在Visual Studio的随机文档里面有介绍,在此不再赘述。三、Windows服务的异常处理 Windows服务没有用户界面,在运行过程中难以将异常通知给用户。通常情况下,Windows服务在运行过程中发生了异常,可能导致服务运行挂起,但没有任何提醒。 推荐的一个做法是在Windows服务中捕获异常,并把异常信息写在Windows的事件日志中。打开Windows的“控制面板/管理工具/事件查看器”,系统显示Windows事件日志。
在一个实际的应用中,笔者除了把异常和提示记录在事件日志中,还把严重错误自动通过邮件发送给相关人员。同时,所有记录在事件日志中的信息,还重定向到一个自行开发的控制台程序中,用以随时监控服务。
三、Windows事件日志的开发要点和技巧 Visual Studio的随机文档里,在介绍Windows服务程序的开发步骤的同时,也介绍了如何向Windows服务中加入事件日志,笔者不再赘述。开发要点如下: 1、在需要写入日志的类中创建EventLog的实例eventLog,在构造函数里加入代码: if (!System.Diagnostics.EventLog.SourceExists('mySource')) { System.Diagnostics.EventLog.CreateEventSource('mySource','myEventLog'); } eventLog.Source = ' mySource '; eventLog.Log = ' myEventLog '; 2、在需要写事件日志的地方写日志,例如: protected override void OnStop() { eventLog.WriteEntry('In onStop.'); } 读者可以在实际应用中尝试使用下面的技巧。 1、把写Windows事件日志的代码封装成独立的class,这样不仅在Windows服务中,而且在其他的业务代码中都可以使用Windows事件日志。代码见附件。 2、为方便调试和跟踪,Visual Sdudio提供了Trace类。在应用程序的debug编译版本中,用Trace类可以把调试和跟踪信息写到控制台。有一个技巧,可以同时把写入Trace的内容写入Windows事件日志。要点如下: 首先声明一个事件监听类EventLogTraceListener的实例, static private EventLogTraceListener cTraceListener = new EventLogTraceListener( m_eventLog ); 将EventLogTraceListener的实例加入Trace的监听列表: Trace.Listeners.Add( cTraceListener ); 此后,凡是写入Trace的调试信息,均写入Windows事件日志中。如果不希望将Trace继续写入事件日志,运行下面代码即可: Trace.Listeners.Remove( cTraceListener ); 3、写入事件日志的信息,还可以同时写入其他应用程序窗体中的显示控件。 首先打开窗体的设计视图,从工具箱/组件中选择EventLog并加入窗体,配置EventLog的EnableRaisingEvents属性为True。 加入EventLog的EntryWritten事件处理方法,该事件的第二个参数类行为System.Diagnostics.EntryWrittenEventArgs,其中包含了Windows事件日志条目中的必要内容,将该内容显示在窗体中的某个显示控件中即可。示例代码如下:/// <summary>/// 监听事件日志/// </summary>/// <param name='sender'></param>/// <param name='e'></param>private void eventLog_EntryWritten(object sender, System.Diagnostics.EntryWrittenEventArgs e){ try { // 把日志内容写到名为listEventLog的List控件中 listEventLog.Items.Insert( 0, e.Entry.TimeWritten + ' ' + e.Entry.Message ); // List控件保存不超过500行的日志 while( listEventLog.Items.Count > 500 ) { listEventLog.Items.RemoveAt( listEventLog.Items.Count-1 ); } } catch( Exception ex ) { MessageBox.Show( ex.Message ); }}四、与Windows服务的通讯 在应用程序或其他服务中,可以与Windows服务通讯,包括: 管理Windows服务的生命期,即开启、停止、暂停和重启服务; 获得Windows服务的属性和状态; 获得特定计算机上的服务列表; 向特定的服务发送命令。 这些操作是通过ServiceController 类完成的。ServiceController是一个可视化控件,可以在工具箱中找到。 比较有意思的是ServiceController 中ExecuteCommand这个方法,调用这个方法,可以向Windows服务发送命令,指挥Windows服务的一些操作。例如,在Windows服务的入口类中有一个复写OnCustomCommand()的方法: /// <summary> /// 执行用户自定义消息 /// </summary> /// <param name='command'>消息编号</param> protected override void OnCustomCommand( int command ) { try { switch( command ) { case 1: // 业务操作 doBusiness1(); break; case 2: //业务操作 doBusiness2(); break; default: …… break; } } catch( Exception ex ) { // 错误信息 string strErrorMsg = string.Format('异常:{0}\n', ex.Message ); // 写日志 TLineEventLog.DoWriteEventLog( strErrorMsg, EventType.Error ); // 给管理员发邮件 CMail.SendMail( PropertyManager.strMailFromAddress, PropertyManager.strMailAdminAddress, '', '异常信息提示',strErrorMsg ); // 写Trace Trace.WriteLine( strErrorMsg ); } } 在另外一个应用程序中通过ServiceController的ExecuteCommand()方法向这个Windows服务发送命令: myController.ExecuteCommand(2); Windows服务将执行业务方法:doBusiness2(); 应该承认,利用ServiceController与Windows服务通讯的功能目前还十分薄弱。通过ExecuteCommand只能与Windows服务进行简单而有限的通讯。 笔者在实际的应用中,分别用一个命令行程序、一个控制台程序和一个Webservice和Windows服务进行通讯,启动、停止服务,或通过ExecuteCommand控制服务的行为。
附件:操纵Windows事件日志的通用类using System;using System.Diagnostics;using System.Configuration; namespace MYCOMMON.EVENTLOG{ public enum EventType { Error,Information,Warning } /// <summary> /// /// </summary> public class TLineEventLog { // 任务日志 static private EventLog m_eventLog = new EventLog(); // 源名称,从配置文件中读取 static private string m_strEventSource = ConfigurationSettings.AppSettings['f_eventLog.Source'].ToString().Trim(); // 日志名称,从配置文件中读取 static private string m_strEventLog = ConfigurationSettings.AppSettings['f_eventLog.Log'].ToString().Trim(); // 调试信息写入日志 static private EventLogTraceListener cTraceListener = new EventLogTraceListener( m_eventLog ); // 缺省构造函数。配置文件读取失败时,提供默认的源名称和日志名称 public TLineEventLog() { if( m_strEventSource.Length == 0 ) m_strEventSource = 'mySource'; if( m_strEventLog.Length == 0 ) m_strEventLog = 'myLog'; m_eventLog.Source = m_strEventSource; m_eventLog.Log = m_strEventLog; } // 构造函数。提供源名称和日志名称。 public TLineEventLog( string strEventSource, string strEventLog ) { m_strEventSource = strEventSource; m_strEventLog = strEventLog; m_eventLog.Source = m_strEventSource; m_eventLog.Log = m_strEventLog; } /// <summary> /// 写事件日志 /// </summary> /// <param name='strMessage'>事件内容</param> /// <param name='eventType'>事件类别,错误、警告或者消息</param> static public void DoWriteEventLog( string strMessage, EventType eventType ) { if (!System.Diagnostics.EventLog.SourceExists( m_strEventSource )) { System.Diagnostics.EventLog.CreateEventSource( m_strEventSource,m_strEventLog ); } EventLogEntryType entryType = new EventLogEntryType(); switch(eventType) { case EventType.Error: entryType = EventLogEntryType.Error; break; case EventType.Information: entryType = EventLogEntryType.Information; break; case EventType.Warning: entryType = EventLogEntryType.Warning; break; default: entryType = EventLogEntryType.Information; break; } m_eventLog.WriteEntry( strMessage, entryType ); } /// <summary> /// 写事件日志,默认为消息 /// </summary> /// <param name='strMessage'>事件内容</param> static public void DoWriteEventLog( string strMessage ) { if (!System.Diagnostics.EventLog.SourceExists( m_strEventSource )) { System.Diagnostics.EventLog.CreateEventSource( m_strEventSource,m_strEventLog ); } m_eventLog.WriteEntry( strMessage ); } /// <summary> /// 调试信息写入日志 /// </summary> public static void OpenTrace() { if( cTraceListener != null ) { if( !Trace.Listeners.Contains( cTraceListener ) ) { Trace.Listeners.Add( cTraceListener ); } } } /// <summary> /// 调试信息不写入日志 /// </summary> public static void CloseTrace() { if( Trace.Listeners.IndexOf(cTraceListener) >= 0 ) { Trace.Listeners.Remove( cTraceListener ); } } }} 作者简介:张昱,联想利泰软件公司(原联想软件设计中心) e-zhangyu@vip.sina.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有