windows服务

关于windows服务的创建相关资源很多,园子里面也有很多这样的文章。
整理了一下相关blog如下,
http://www.cnblogs.com/wuxilin/archive/2006/06/04/416838.html
http://www.cnblogs.com/wujm/archive/2005/05/12/154369.html
http://www.cnblogs.com/caca/archive/2005/02/25/109028.html
http://www.cnblogs.com/laiwen/archive/2005/08/21/219590.html

归纳一下步骤大概如下:
1.创建服务:
1.1我们应该创建windows服务类型的project,IDE会自动从serviceBase类继承一个类出来,在这个类里面有on_star和on_stop两个方法,可以在里面写入启动逻辑和停止逻辑
在设计视图下我们可以修改service的属性
Autolog                 是否自动写入系统的日志文件
CanHandlePowerEvent     服务时候接受电源事件
CanPauseAndContinue     服务是否接受暂停或继续运行的请求
CanShutdown             服务是否在运行它的计算机关闭时收到通知,以便能够调用 OnShutDown 过程
CanStop                 服务是否接受停止运行的请求
ServiceName             服务名
1.2选择服务组件,并切换到设计模式,右键->Add Installer,生成安装文件。安装文件中的属性修改可以参考下面的内容:
projectInstall参数修改Account(指定用户还是使用本地系统用户)
ServiceInstall参数修改:
描述名:Description,
显示名:DisplayName,
ServiName:服务名,要和刚才建立的服务名一一对应才行
StartType:(Manual:服务安装后,必须手动启动.Automatic:每次计算机重新启动时,服务都会自动启动;Disabled:服务无法启动)

2安装
安装服务要使用微软提供的工具InstallUtil,这个工具在c:/windows/wicrosoft.net/framework/[version]中
使用InstallUtil 安装,使用InstallUtil /u 反安装服务

如果还有什么可以参考刚才说的那几个blog,ok一切都很简单。但是如果要做为一个企业级的应用,往往会有别的场景需求,下面说一下我曾碰到的场景要求
1.我们的windows服务可能不止满足一种业务逻辑,比如:如果你的机器安装了oracle的话,就会有OracleService服务,我们启动数据库的时候可以只是启动tns服务和OracleService服务就可以了,但是实际上启动OracleService服务的同时会启动好几个服务,例如:DBWR(数据文件写入),LGWR(日志文件写入),SMON(系统监护),PMON(用户进程监),CKPT(检查点,同步数据文件,日志文件,控制文件等)。有时为了性能的考虑,一个服务也可能要多线程的运行业务逻辑。比如一个导入文件的数据接口服务,如果数据量非常大就要这样考虑。一般如果执行多个任务,可以有两种方法:1.开多个线程;2.在一个线程中顺序进行(可以加上时间控制)。我觉得这里最灵活的方法是用.net本省的多线程支持来解决。
2.要能在不改变系统结构的情况下,可以非常快速的支持新的服务要求。这说明我们在onstar方法中不能写入相关类的处理逻辑,必须要用某种方法解耦才行。

实现方法:
参考下面的类图

servcive类和具体的业务实现类解耦,我们可以使用工厂模式生成业务逻辑类,每个业务逻辑类启动在一个新的线程中,在.net中工厂模式可以用反射非常方便的实现,这块代码如下:

typeInfo = node.Attributes["type"].Value;
                    Type type 
= Type.GetType(typeInfo);
                    IService instance 
= (IService)Activator.CreateInstance(type);
                    
//初始化服务
                    instance.Initialize(node);
                    instanceArray.Add(instance);

                    
//在新线程中运行服务,每个服务使用相同的安全上下文
                    ThreadStart ts = new ThreadStart(instance.Start);
                    Thread t 
= new Thread(ts);
                    t.Start();


从配置文件中读出需要加载的业务逻辑类,实例化后用ThreadStart调用其中的Start方法,启动新线程。这里对配置文件的读取如果要求比较高可以采用Enterprise Libary的Login block来做。
在OnStop方法中调用每个类的Stop方法,如果想对每个Stop方法异步调用,可以用delegate封装接口的Stop方法用
BeginInvoke方法实现异步调用

  foreach (object o in instanceArray)
   
{
    
try
    
{
     IService service 
= (IService)o;
     
if (service !=null)
     
{
            
//异步调用每个服务的stop方法来停止业务组件
      OnStopDelegate osd = new OnStopDelegate(service.Stop);
      osd.BeginInvoke(
null,null);
     }

    }

    
catch (Exception ex)
    
{
     
//
    }

   }


这样,整个windows服务就实现了,这里还有个额外的好处是可以热部署,即不需要删除已经部署的windows服务,将新的DLL覆盖将以前的DLL覆盖,修改*.exe.config文件并重新启动就可以了。其实我觉得停止服务,重新编译部署后在启动服务花费的时间可能比这样还少些。

关于调试:
windows服务常用的调试方法是用调试->附加到进程的方法。
选择显示所有用户进程,我们已经部署并启动的windows服务进程就会出现,并跳到我们设置好的断点处。但是这样对service中的onstart部分调试比较麻烦。我还是推荐创建一个porjec做为调试用,这里面可以写onstart部分的代码,代码不多,非常方便。大家就可以象调试普通windows程序一样调试这windows服务代码了



调试windows service的OnStart事件.

    关于调试windows service, 其实这是一个老生常谈的问题了.

    通常的处理办法是, 在service运行后, 在调试器中选择attach to process.

    然而这种做法也有一定的局限性, 例如在service启动时的OnStart事件中的代码, 基本上很难调试. 往往当attach到我们的service的时候, 这部分代码已经执行过了. 于是, 有人提出, 可以另写一个project来调用这个OnStart方法, 或将OnStart方法中的代码搬到另一个project中测试. 不过, 这些方法终究不是以windows服务的方式调试的, 不能够最真实的反应service运行时的执行状况(如权限问题等环境问题).

    我的做法是, 在OnStart方法的最开始部分加上"Debugger.Launch()"的调用, 当service运行到此处时, 将会弹出一个选择调试器的对话框, 同时暂停在当前位置. 这样, 我们就做到了在代码中手动的启动调试器.

    示例代码如下:

using System.Diagnostics;
 
public partial class MyService : ServiceBase{
    public MyService(){
        InitializeComponent();
    } 
 
    protected override void OnStart(string[] args){
#if DEBUG
        Debugger.Launch();    //Launches and attaches a debugger to the process.
#endif
        // TODO: add your initialize code here.
    } 
 
    protected override void OnStop(){
    }

} 

posted @ 2009-03-25 15:02  Microbar  阅读(484)  评论(0编辑  收藏  举报