使用Visual Studio 2015 Community 开发windows服务

  昨天研究在.NET下开发Windows服务程序,期间遇到一些小问题,这里仅将自己的开发过程和需要注意的地方写下和广大网友分享……

1、基础

    Windows服务是指系统启动时能够自己运行的程序。Windows服务可以在没有交互界面的情况下在后台进行业务的处理。

  .NET下开发Windows服务需要几个基本的类,它们在程序集System.ServiceProcess.dll和System.Configuration.Install.dll中,分别是:ServiceBase、ServiceInstaller、ServiceProcessInstaller、Installer,这几个类是开发一个最简单的Windows服务所必须的。

2、使用Visual Studio 2015 Commnuity创建Windows服务项目

  在Classic Desktop(经典桌面程序)中选择Windows Service项目。项目文件结构如下:

  双击Service1.cs进入服务设计界面,设置ServiceName属性(该属性在下文中还会提及,请留意),该属性是系统控制Windows服务的标识:

  这里我将ServiceName属性设置为Test,大家注意看属性面板的上边,发现这里设置的是ServiceBase类的属性。ServiceBase类是.NET中创建所有Windows服务的基类。在创建新的服务类时,必须从 ServiceBase 派生。

  接下来我们看下Service1.cs文件的代码部分,可以看到里面有个Service1类继承自ServiceBase类,还有两个重写方法,OnStart和OnStop。OnStart中的代码将会在服务启动之后运行,OnStop中的代码在服务停止时运行。除此之外还有OnPause、OnContinue等方法。这是我们编译项目会在bin\Dubug文件夹下生成WindowsService1.exe文件,这个文件就是我们创建的Windows服务。是不是感觉很简单?但是如果你以为Windows服务的创建工作到此为止就结束了,那就错了。不信双击WindowsService1.exe运行试试……

3、Windows服务的安装

  看到了吧,提示我们想要运行Windows服务要先安装该服务

  提示信息中提到了installutil.exe,这里先不说它的用处。我们要想安装刚刚创建的Windows服务,首先要在项目中创建安装文件,如图:

  双击刚刚创建的Installer1.cs文件会进入它的设计界面,这里且不管设计界面,我们直接进入代码界面,会看到里面有一个类:Installer1,它继承自

System.Configuration.Install命名空间下的Installer类,Installer 类是 .NET中所有自定义安装程序的基类。

  首先我们在Installer1的构造函数中定义我们的服务进程安装类(即上文提到的ServiceProcessInstaller)实例和服务安装类(即上文提到的ServiceInstaller)实例

        public Installer1()
        {
            InitializeComponent();

            ServiceProcessInstaller spi = new ServiceProcessInstaller();
            spi.Account = ServiceAccount.LocalSystem;//设置服务要运行在什么类型的账号下

            //这里可以创建多个ServiceInstaller实例
            ServiceInstaller si = new ServiceInstaller();
            si.ServiceName = "Test";//系统操作服务的标识,要和ServiceBase中设置的ServiceName属性值相同
            si.DisplayName = "测试服务";//展示给用户的服务名,即在控制面板中看到的服务名
            si.Description = "服务的描述信息";
            si.StartType = ServiceStartMode.Manual;//服务的启动方式,这里设置为手动

            //最后记得把创建的实例添加到安装列表中
            this.Installers.Add(si);
            this.Installers.Add(spi);
        }

  到此,对于安装服务的基本信息已经填写完毕。接下来我们还需要重写基类Installer中的两个方法:

        //注意必须重写Install和Uninstall方法,且在重写方法中必须调用基类对应的方法,否则在安装和卸载服务的过程中会出问题
        //小编就是因为没有调用基类中的方法导致安装和卸载出现问题
        //出此之外还有Commit、Rollback等方法
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
        }

        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
        }    

  这里大家要注意一点,在Installer1类上使用了特性:RunInstaller(true),如果我们将特性的参数设为false,那么安装工具installutil将会忽略该类,我们在安装服务时就不会安装该类中指定的服务。

  完成上述步骤之后,我们再次编译项目……

  在上文中我们提到了installutil.exe工具,它是用来安装.NET编写的Windows服务的工具,它的路径是C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe。其中v4.0.30319是.NET的版本号,使用不同版本的.NET编写Windows服务要使用对应的installutil.exe来安装。

  我们打开命令行或使用VS自带的命令行工具,这里我们使用VS自带的命令行工具:Developer Command Prompt for VS2015来进行安装工作。

  打开命令行工具,输入:installutil.exe Windows服务程序的路径(这里小编涂去了和个人信息相关的部分)然后回车

  如使用系统的命令行工具就需要先跳转到installutil.exe所在的路径或者在命令行中指明它的路径。

  回车之后会发现,Windows服务开始安装了,在然后就会发现安装出现了问题……

  对于这个问题的解决方式相当简单,就是以管理员身份运行命令行工具即可(小编却花费了很长的时间才悟出来这个道理)。

  以管理员身份运行命令行,再次执行安装过程,我们可以看到安装过程分为:安装和提交两步。

  安装完成之后,我们可以在控制面板的服务管理器中看到刚刚安装的服务:

  安装完成之后我们来启动服务,这里使用命令行来启动,也可以在服务管理器中启动。

  大家注意到没有?控制面板服务管理器中显示的服务名称是DisplayName属性指定的名称,而我们启动服务时要使用ServiceName属性指定的服务名,否则会提示我们服务名无效。

  服务的停止使用命令:net stop 服务名称。

  服务的卸载使用installutil /u 服务程序路径来完成。

  至此,在.NET中开发一个简单的Windows服务的工作已经全部完成……

版权声明

本文为作者原创,版权归作者雪飞鸿所有。 转载必须保留文章的完整性,且在页面明显位置处标明原文链接

如有问题, 请发送邮件和作者联系。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

ASP.NET Web API 处理架构

这篇文章主要是介绍ASP.NET Web API的处理架构:当一个HTTP请求到达直到产生一个请求的过程。ASP.NET Web API 的处理架构图如下,主要...

2998
来自专栏林德熙的博客

Roslyn 如何在 Target 引用 xaml 防止文件没有编译

在使用新的项目格式,可以使用 Target 添加项目,但是有一些项目需要在合适的时候添加,如果添加早了,那么会让用户看到这些文件,如果添加的时间是在引用编译之后...

891
来自专栏大内老A

关于WCF的一个非常“无语”的BUG!

这确实是一个让人觉得“无语”的BUG,甚至让我觉得微软在故意和我们开玩笑。这个问题在我刚刚接触WCF的时候就遇到过,换言之,这个问题一直存在于.NET 3.0、...

2057
来自专栏转载gongluck的CSDN博客

程序的入口

操作系统装载应用程序后,做完初始化工作就转到程序的入口点执行。程序的默认入口点由连接程序设置, 不同的连接器选择的入口函数也不尽相同。在VC++下,连接...

3779
来自专栏蘑菇先生的技术笔记

那些年我们一起追过的缓存写法(四)

2896
来自专栏数据分析

[译]Asp.net MVC 之 Contorllers(二)

URL路由模块 取代URL重写 路由请求 URL路由模块的内部结构 应用程序路由 URL模式和路由 定义应用程序路由 处理路由 路由处理程序 处理物理文件请求 ...

3956
来自专栏Java帮帮-微信公众号-技术文章全总结

IntelliJ IDEA 设置JVM运行参数

打开 IDEA 安装目录,看到有一个 bin 目录,其中有两个 vmoptions 文件,需针对不同的JDK进行配置:

6403
来自专栏追不上乌龟的兔子

用.NET Core构建安全的容器化的微服务

微服务热潮正在如火如荼地进行,也有着充分的理由。它不是每个问题的银弹,但它无疑成为企业软件系统中可扩展性和弹性的实用解决方案。

4104
来自专栏Java帮帮-微信公众号-技术文章全总结

02.Linux安装

02.Linux安装 Linux 安装 本章节我们将为大家介绍Linux的安装。 本章节以 centos6.4 为例。 centos 下载地址: 可以去官网下载...

71011
来自专栏草根专栏

asp.net core 2.0 查缺补漏

asp.net core 2.0 一些有用有趣的设置. 面向(targeting)不同的.net版本: 打开asp.net core 2.0的项目文件: xxx...

3095

扫码关注云+社区

领取腾讯云代金券