关于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方法中不能写入相关类的处理逻辑,必须要用某种方法解耦才行。

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





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

windows服务
    





		
调试windows service的OnStart事件.typeInfo = node.Attributes["type"].Value;
windows服务
    





		
调试windows service的OnStart事件.                    Type type 
= Type.GetType(typeInfo);
windows服务
    





		
调试windows service的OnStart事件.                    IService instance 
= (IService)Activator.CreateInstance(type);
windows服务
    





		
调试windows service的OnStart事件.                    
//初始化服务
windows服务
    





		
调试windows service的OnStart事件.
                    instance.Initialize(node);
windows服务
    





		
调试windows service的OnStart事件.                    instanceArray.Add(instance);
windows服务
    





		
调试windows service的OnStart事件.
windows服务
    





		
调试windows service的OnStart事件.                    
//在新线程中运行服务,每个服务使用相同的安全上下文
windows服务
    





		
调试windows service的OnStart事件.
                    ThreadStart ts = new ThreadStart(instance.Start);
windows服务
    





		
调试windows service的OnStart事件.                    Thread t 
= new Thread(ts);
windows服务
    





		
调试windows service的OnStart事件.                    t.Start();
windows服务
    





		
调试windows service的OnStart事件.


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

windows服务
    





		
调试windows service的OnStart事件.  foreach (object o in instanceArray)
   
    try
    
     IService service = (IService)o;
windows服务
    





		
调试windows service的OnStart事件.     
if (service !=null)
     
            //异步调用每个服务的stop方法来停止业务组件
windows服务
    





		
调试windows service的OnStart事件.
      OnStopDelegate osd = new OnStopDelegate(service.Stop);
windows服务
    





		
调试windows service的OnStart事件.      osd.BeginInvoke(
null,null);
windows服务
    





		
调试windows service的OnStart事件.     }

windows服务
    





		
调试windows service的OnStart事件.    }

windows服务
    





		
调试windows service的OnStart事件.    
catch (Exception ex)
    
     //
windows服务
    





		
调试windows service的OnStart事件.
    }
windows服务
    





		
调试windows service的OnStart事件.   }


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

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



    关于调试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(){
    }

} 

相关文章: