使用C#调试Windows服务模板项目
Windows服务是非常强大的应用程序,可用于在backgorund中执行许多不同类型的任务。他们可以在不需要任何用户登录的情况下启动,并且可以使用除登录用户之外的其他用户帐户运行。但是,如果通过遵循常规服务开发步骤开发Windows服务应用程序,即使在开发环境中也难以调试。
本文提出了一种不使用任何服务开发库(如Topshelf)开发Windows服务的不同方法,以便在开发阶段轻松监视和调试。
特征
示例项目具有以下功能;
- 它在调试模式下作为控制台应用程序运行,在发布模式下作为常规Windows服务运行。
- 根据日志类型在控制台上显示具有不同文本颜色的日志消息。
- Windows服务相关操作和实际后台任务处理操作是分开的,因此可以轻松地对实际服务操作进行单元测试。
- 可以使用InstallUtil.exe安装和卸载服务。但是您不需要安装它来进行测试和调试。
准备此应用程序的步骤
示例项目网站源码是使用Visual Studio 2017准备的。
1-创建Windows服务项目
在Visual Studio中,单击“文件”\“新建”\“项目”。选择“Visual C#\ Windows桌面\ Windows服务”项目类型。
2-将项目输出类型从Windows应用程序更改为控制台应用程序
右键单击项目名称并选择“属性”,打开项目属性。
从“输出类型”选择列表中选择控制台应用程序。
3-安装log4net软件包
从Package Manager控制台或Manage Nuget Packages菜单选项安装log4net nuget软件包。
4-配置log4net
log4net是一个非常强大的日志库,可以将日志写入许多目标,如文本文件,控制台,数据库,Windows事件日志,甚至可以将它们作为电子邮件发送。这些日志编写器(或目标)称为“appender”。log4net配置必须至少有一个appender,但它可能有很多。每个appender都有自己的设置。
log4net配置可以添加到app.config文件中,也可以是单独的文件。我更喜欢单独的文件方法,因此为log4net添加两个配置文件,用于调试和发布模式。名称无关紧要,您可以将它们命名为“ log4net.debug.config ”和“ log4net.prod.config ”。Debug配置文件有两个appender; RollingFileAppender
和 ColoredConsoleAppender
。生产配置文件还有两个appender; RollingFileAppender
和 EventLog
。但 EventLog
appender已注释掉,如果要编写Windows事件日志,可以取消注释。
最小日志级别在<root>
元素下定义为<level>
配置元素。对于调试配置级别是DEBUG,对于生产它是INFO
。有效等级是; DEBUG
,INFO
,WARN
,ERROR
。有关详细信息,请参阅log4net文档。
下一步配置步骤是告诉log4net库在调试和释放模式下使用哪个文件。为此,请打开AssemblyInfo.cs文件并为log4net添加程序集级别属性。添加这些行以在调试和释放模式下在两个文件之间切换。
#if DEBUG
[ assembly:log4net.Config.XmlConfigurator(ConfigFile = “ log4net.debug.config”,Watch = true)]
#else
[ assembly:log4net.Config.XmlConfigurator(ConfigFile = “ log4net.prod.config”,Watch = 真的)]
#endif
5-添加SampleBackgroundService类,其中包含我们的Windows服务将执行的实际后台操作。
它是一个非常简单的类 Start
,Stop
用于启动和停止后台任务处理线程的方法以及连续写入日志的线程方法。
class SampleBackgroundService
{
// 从log4net获取此类的记录器LogManager
private static ILog logger = LogManager.GetLogger(typeof(SampleBackgroundService)); // 启动线程
public void Start(){...} // 停止线程
public void Stop(){...} // 执行后台任务并写入日志的服务线程
private void serviceThread()
{
while(!stopRequested)
{
// 写出不同类型的日志......
}
}
}
6-更新自动生成的Windows Service类中的代码
我已将自动添加的Windows Services类重命名为 SampleWindowsService
。此类继承自ServiceBase
,并且是在启动或停止Windows服务时调用其方法OnStart
和类的类OnStop
。该类仅创建类的实例 SampleBackgroundService
并调用其Start
和Stop
方法。
7-更新Program.cs文件中的Main mathod,使其在Debug和Release模式下表现不同
创建新的Windows服务项目时,自动生成的Main方法包含用于创建和启动自动生成的Windows服务的代码。但是,Windows服务无法作为常规应用程序启动和托管。因此,当您尝试运行该应用程序时会出现一条错误消息。
要运行和测试我们的应用程序,我们不需要创建真正的Windows服务实例,因为除了创建和启动SampleBackgroundService
类的实例之外,它不包含任何代码 。Main方法中更新的代码在SampleBackgroundService
Debug模式下创建并启动类的实例, 并作为控制台应用程序运行。但是在发布模式下创建并运行真正的Windows服务。
static void Main()
{
ILog logger = LogManager.GetLogger(typeof(Program)); #if DEBUG //在调试模式下作为常规控制台应用程序运行
// 手动创建SampleBackgroundService类的实例并调用其start方法 logger.Info(“正在启动服务......”); SampleBackgroundService _backgroundService = new SampleBackgroundService ();
_backgroundService.Start(); logger.Info(“ 服务已启动。按Enter键停止...”);
到Console.ReadLine(); logger.Info(“ 停止服务......”);
_backgroundService.Stop();
logger.Info(“已停止。”); #else //在Release模式 ServiceBase [] ServicesToRun中创建并运行真正的Windows服务实例
;
ServicesToRun = new ServiceBase []
{
新的 SampleWindowsService()
};
ServiceBase.Run(ServicesToRun);
#endif
}
8-添加Service Installer组件,以便能够使用InstallUtil.exe安装此服务
要添加安装程序组件,请在解决方案资源管理器上双击SampleWindowsService.cs。它将显示服务的设计视图。
右键单击设计区域,然后单击上下文菜单中的“添加安装程序”。
这会将ProjectInstaller.cs和设计器文件添加到项目中。删除自动生成的代码 ProjectInstaller.InitializeComponent()
方法和自动生成的变量(serviceProcessInstaller1
,serviceInstaller1
)。
将以下代码添加到 ProjectInstaller.cs文件中;
public partial class ProjectInstaller:Installer
{
public const string SERVICE_NAME = “ Sample Background Service” ; private readonly ServiceProcessInstaller m_ServiceProcessInstaller;
private readonly ServiceInstaller m_ServiceInstaller; public ProjectInstaller()
{
// 安装进程的安装程序(在本例中为'DebuggableWindowsService.exe')
// 只能有一个ServiceProcessInstaller
m_ServiceProcessInstaller = new ServiceProcessInstaller();
m_ServiceProcessInstaller.Account = ServiceAccount.LocalSystem; // 在应用程序中注册实际Windows服务实现的安装程序
// 可能有一个或多个ServiceInstaller
m_ServiceInstaller = new ServiceInstaller();
m_ServiceInstaller.ServiceName = SERVICE_NAME;
m_ServiceInstaller.Description = “ ” ;
m_ServiceInstaller.StartType = ServiceStartMode.Automatic;
m_ServiceInstaller.DelayedAutoStart = true ; Installers.Add(m_ServiceProcessInstaller);
Installers.Add(m_ServiceInstaller); 的InitializeComponent();
} // ... }
如果要在安装服务之前和之后执行任何任务,可以覆盖适当的基本方法,例如 OnBeforeInstall
, OnBeforeUninstall
...
您无需安装(或向Windows服务注册表注册服务)您的服务即可运行和调试。但是,如果需要,可以使用InstallUtil.exe来安装和卸载服务。InstallUtil.exe位于.NET Framework安装文件夹下。例如,“ C:\ Windows \ Microsoft.NET \ Framework \ v4.0.30319 ”
要注册该服务,请打开命令行窗口并使用可执行文件的完整路径运行InstallUtil.exe。您可能需要“以管理员身份”运行命令行窗口才能注册服务。
C :\ Windows \ Microsoft.NET \ Framework \ v4.0.30319> InstallUtil.exe“D:\ DebuggableWindowsService \ src \ bin \ Release \ DebuggableWindowsService.exe”
要卸载服务,请使用/ u选项运行相同的命令。
C :\ Windows \ Microsoft.NET \ Framework \ v4.0.30319> InstallUtil.exe / u“D:\ DebuggableWindowsService \ src \ bin \ Release \ DebuggableWindowsService.exe”
9-在调试模式下运行应用程序以查看日志输出和调试
下面是在调试模式下运行应用程序时显示的示例输出。
关于Windows服务的重要说明
Windows Service应用程序在几个方面与其他常规应用程序不同。因此,应用程序在调试(控制台应用程序模式)和发布(Windows服务模式)模式下的行为可能不同。
首先,当您在调试模式下运行应用程序时,其工作目录将是可执行文件所在的路径。例如“ D:\ DebuggableWindowsService \ src \ bin \ Release \ DebuggableWindowsService.exe ”
但是,当您使用InstallUtil.exe或安装应用程序安装它并从Windows服务管理应用程序运行它时,其工作目录将是“ C:\ Windows \ System32 ”或“ C:\ Windows \ SysWOW64 ”,具体取决于您的服务是64位32d无论是在32位还是64位Windows上运行。
如果要在安装目录中读取或写入文件而不是系统目录,则可以在启动时使用工作目录。例如;
Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly()。Location);
其次, Windows服务可以使用除登录用户之外的其他用户帐户运行。当应用程序rusn作为真正的Windows服务时,某些在调试模式下运行的操作可能无法运行。这些操作的示例是访问目录或网络路径,打开端口......
第三, Windows服务没有用户界面,通常无法显示用户界面。Windows操作系统阻止了他们对显卡的访问。遗憾的是,无法使用Windows服务中的强大GPU。要了解有关此限制的更多信息,请搜索“会话0隔离”。
使用C#调试Windows服务模板项目的更多相关文章
- Windows服务二:测试新建的服务、调试Windows服务
一.测试Windows服务 为了使Windows服务程序能够正常运行,我们需要像创建一般应用程序那样为它创建一个程序的入口点.像其他应用程序一样,Windows服务也是在Program.cs的Main ...
- c#创建、安装、卸载、调试windows服务的简单事例
最近工作中用到了windows服务,对其有深刻理解和丰富经验谈不上,本篇文章只是简单陈诉用c#创建.安装.卸载.调试windows服务的步骤. 一.创建windows服务 1.用VS创建windows ...
- C# Asp.net Quartz.NET作业调度之创建、安装、卸载、调试windows服务的简单事例
一.创建windows服务 1.用VS创建windows服务,结果如下: 2.删除默认生成的Service1.cs文件,然后创建自己的服务文件(如:MyService),并修改Program.cs文件 ...
- 如何调试 Windows 服务
概要 本文分步介绍了如何使用 WinDbg 调试程序 (windbg.exe) 调试 Windows 服务. 要调试 Windows 服务,可以在服务启动后将 WinDbg 调试程序附加到托管该服务的 ...
- .net Windows服务程序和安装程序制作图解 及 VS 2010创建、安装、调试 windows服务(windows service)
.net Windows服务程序和安装程序制作 最近项目中用到window服务程序,以前没接触过,比较陌生,花了两天的时间学习了下,写了个简单的服务,但在制作安装程序的时候,参照网上很多资料,却都制作 ...
- VS创建、安装、调试 windows服务(windows service)
1.创建 windows服务 项目 文件 -> 新建项目 -> 已安装的模板 -> Visual C# -> windows ,在右侧窗口选择"windows 服 ...
- C# VS 2010创建、安装、调试 windows服务(windows service)
在一个应用程序中创建多个 windows 服务的方法和 1083 的解决办法 错误解决方案 ------------------------------------------------------ ...
- c# windows服务 一个项目安装多个服务
创建windows服务就不讲解了,其它大神写太多了.这里只写一个项目安装多个服务的教程.如:http://www.cnblogs.com/zzgblog/p/4595839.html 首先按下图创建多 ...
- 调试windows服务最简单的方法之一
先看一下这段启动代码: using System; using System.Collections.Generic; using System.Linq; using System.ServiceP ...
随机推荐
- CS224n笔记二:word2vec
如何表示词语的意思 语言学中meaning近似于"指代,代指,符号". 计算机中如何处理词语的意思 过去一直采用分类词典,计算语言学中常见的方式时WordNet那样的词库,比如NL ...
- 用 eric6 与 PyQt5 实现python的极速GUI编程(35篇PyQT和200多篇Python)
[题记] 我是一个菜鸟,这个系列是我的学习笔记. PyQt5 出来有一段时间了, PyQt5 较之 PyQt4 有一些变化,而网上流传的几乎都是 PyQt4 的教程,照搬的话大多会出错. eric6 ...
- 深入浅出RPC——深入篇(转载)
本文转载自这里是原文 <深入篇>我们主要围绕 RPC 的功能目标和实现考量去展开,一个基本的 RPC 框架应该提供什么功能,满足什么要求以及如何去实现它? RPC 功能目标 RPC的主要功 ...
- 【Linux】Linux下跟踪记录每个用户对主机服务器进行的操作
linux中跟踪每个用户对主机的操作,看有人之前已经写过如此shell,可直接参考,参考如下: 1.记录操作信息 这个脚本需添加至/etc/profile 脚本如下: history USER_IP= ...
- Android开发需要了解的 IM 知识
引言 即便在通讯如此发达的今天,IM 也依然是诸多场景下非常重要的基础能力.因此做为 一名 Android 开发,不可避免的会遇到一些IM 相关的需求或问题.本文以一个Android开发的角度来讲述I ...
- Linux系统下解锁Oracle的Scott用户
1).在Oracle用户下面输入命令:lsnrctl status查看监听是否开启,如果未开启则需要开启监听,输入命令:lsnrctl start; 2).如果没有设置监听的话需要先建立一个监听,然后 ...
- java集合知识点总结
下面是java中常见的集合: List--列表:内部元素有序,可以重复, ArrayList:线程不安全,效率高.数据结构是线性表,底层结构是顺序表,也就是数组,有唯一的下标来指定元素的位置,查询快, ...
- 图片加载时间缓慢问题API
一.背景 最近段时间,开发写值工具项目中,出现图片加载问题API,响应时间缓慢:为了优化图片加载问题,我进行图片压缩方法,然后API的图片加载还是慢,最终在自己无意中乱写找到了根本的原因. ...
- Ruby系列文章
安装Ruby.多版本Ruby共存.Ruby安装慢问题 Ruby语言的一些杂项 Ruby中的常量:引号.%符号和heredoc Ruby中的数值 Ruby字符串(1):String基本用法 Ruby字符 ...
- SpringMVC_Two
SpringMVC_Two 响应数据和结果视图 创建工厂 导坐标: </load-on-startup> </servlet> <servlet-mapping> ...