欢迎光临
我们一直在努力

编写 Window 服务程序-.NET教程,Windows开发

建站超值云服务器,限时71元/月

编写 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

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 编写 Window 服务程序-.NET教程,Windows开发
分享到: 更多 (0)