编写 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
编写 Window 服务程序-.NET教程,Windows开发
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 编写 Window 服务程序-.NET教程,Windows开发
相关推荐
-      VS2010的aspx文件中的html代码的格式化方法
-      .net 反序题目的详细解答第1/2页
-      asp.net创建html文本文件实例
-      比较完整的 asp.net 学习流程
-      官网 Ext direct包中.NET版的问题
-      C# XML操作 代码大全(读XML,写XML,更新,删除节点,与dataset结合等)第1/2页
-      c# 连接字符串数据库服务器端口号 .net状态服务器端口号
-      asp.net教程:简单的C#图片上传代码或C#文件上传代码