目录
一、概述
二、新建服务程序
三、安装前的准备
四、启动、停止,安装、卸载
五、测试
1.安装项目
2.启动项目
3.停止项目
4.卸载项目
结束
当需要在 Windows 操作系统以后台服务的形式运行某个应用程序时,可以使用 Windows 服务。Windows 服务是一种特殊类型的应用程序,它可以在操作系统启动时自动启动,并在后台持续运行,而无需用户交互。
Windows 服务通常用于执行一些重要的系统任务,例如定期备份数据、监控系统状态、处理消息队列等。它们在后台默默地运行,不会显示用户界面,但可以通过服务管理器进行配置和监视。
编写一个 Windows 服务程序可以使用 C# 编程语言和 .NET 框架。通过使用 .NET 提供的相关类和方法,可以轻松地创建、安装、启动和停止 Windows 服务。 一个典型的 Windows 服务程序包括以下几个关键部分:
1. 服务类:这是一个继承自 System.ServiceProcess.ServiceBase 类的自定义类。在这个类中,需要重写 OnStart 和 OnStop 方法,分别用于处理服务的启动和停止逻辑。在 OnStart 方法中,可以执行服务的初始化操作,并开始执行后台任务。在 OnStop 方法中,可以执行服务的清理操作,并停止后台任务。
2. 服务主程序:这是一个包含 Main 方法的类,用于启动和停止服务。在 Main 方法中,需要创建一个 ServiceHost 对象,并将服务类作为参数传递给它。然后调用 Start 方法启动服务,并通过调用 Stop 方法停止服务。
3. 安装程序:为了将服务安装到 Windows 系统中,需要编写一个安装程序。安装程序将服务的可执行文件注册到系统服务管理器中,并提供安装、卸载和配置服务的功能。 通过编写一个 Windows 服务程序,可以实现在后台运行的应用程序,以便自动执行某些任务或提供某种功能。这种方式可以确保应用程序在系统启动后始终可用,并且无需用户干预。 请注意,编写和部署 Windows 服务需要一些系统管理权限和操作。确保在进行这些操作之前,对系统有足够的了解,并按照最佳实践进行操作。
在新建项目时,选择 Windows 服务,目前只有 .NET Framework 的服务程序,没有 .Net6 的
或者直接搜索“服务”二字
这里就直接用默认的名字吧
创建完成后的界面
选中 Service1.cs 右键选择查看代码,如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
}
这里重写了一个 OnStart 和 OnStop 方法,意思是程序启动的时候执行一次,和程序关闭的时候执行一次。
因为目前只是作为演示,就不用过多的功能,就随便输出一些日志,能理解 Windows 服务的用法就好了。
安装插件 log4net
新建一个类 Logger,用来输出日志
using System;
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", ConfigFileExtension = "config", Watch = true)]
public class Logger
{
private static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("loginfo");
private static readonly log4net.ILog logerror = log4net.LogManager.GetLogger("logerror");
public static void WriteInfo(string info)
{
Console.WriteLine(info);
if (loginfo.IsInfoEnabled)
{
loginfo.Info(info);
}
}
public static void WriteError(string error)
{
Console.WriteLine(error);
if (logerror.IsErrorEnabled)
{
logerror.Error(error);
}
}
public static void WriteError(string info, Exception ex)
{
Console.WriteLine(info);
if (logerror.IsErrorEnabled)
{
logerror.Error(info, ex);
}
}
}
log4net 要想输出日志,还需要另外添加一个配置文件 log4net.config
将 log4net.config 文件设置成:如果较新则复制
服务程序并不能直接启动,安装服务程序需要固定的流程,接下来是安装服务程序的相关内容。
双击 Service1.cs 文件
就打开了 Service1 的设计界面,接着点击 添加安装界面
这时候会自动生成一个 ProjectInstaller 的文件
点击 serviceInstaller1 查看属性
Windows 服务程序主要用到的有几个属性:
Description 服务的说明
ServiceName 服务的名字
StartType 服务的启动类型
这几个属性可以参考下图:
这里我就随便设置下:
再点击 serviceProcessInstaller1,查看属性
将 Account 设置为 LocalService
以上操作完成后,将项目保存,生成程序。
Windows 服务程序一般用控制台进行安装和卸载的,但控制台用起来不是特别方便,这里我就用 Winform 写一个对应的程序好了。
新一个 Winform 项目,名字叫 ServiceControl, 主要用来操作服务程序的启动、停止,安装、卸载。
创建项目完成后,需要添加一个 dll,名字叫 System.ServiceProcess,一般默认情况下在创建项目时是不会主动添加这个 dll 的,在引用管理器中选择程序集,然后搜索,找到之后添加到项目中就好了。
Winform 界面如下:
Form1 代码
using System;
using System.Collections;
using System.Configuration.Install;
using System.IO;
using System.ServiceProcess;
using System.Windows.Forms;
namespace ServiceControl
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//服务程序路径
private string ServiceFilePath = string.Empty;
//服务程序名
private string ServiceName = string.Empty;
private void Form1_Load(object sender, EventArgs e)
{
}
///
/// 选择服务程序路径 点击事件
///
///
///
private void Button_SelectPath_Click(object sender, EventArgs e)
{
string serviceName = TextBox_ServiceName.Text;
if (string.IsNullOrEmpty(serviceName))
{
Console.WriteLine("请先输入服务程序名");
return;
}
ServiceName = serviceName;
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
//文件路径
string filePath = openFileDialog.FileName;
TextBox_ServicePath.Text = filePath;
ServiceFilePath = filePath;
}
}
///
/// 启动服务 点击事件
///
///
///
private void Button_StartService_Click(object sender, EventArgs e)
{
try
{
if (!IsServiceExisted(ServiceName))
{
Console.WriteLine("请先安装服务程序:{0}", ServiceName);
return;
}
ServiceStart(ServiceName);
Console.WriteLine("启动服务 完成");
}
catch (Exception ex)
{
Console.WriteLine("启动服务程序错误:{0}", ex.Message);
}
}
///
/// 停止服务 点击事件
///
///
///
private void Button_StopService_Click(object sender, EventArgs e)
{
try
{
if (!IsServiceExisted(ServiceName))
{
Console.WriteLine("请先安装服务程序:{0}", ServiceName);
return;
}
ServiceStop(ServiceName);
Console.WriteLine("停止服务 完成");
}
catch (Exception ex)
{
Console.WriteLine("停止服务程序错误:{0}", ex.Message);
}
}
///
/// 安装服务 点击事件
///
///
///
private void Button_InstallerService_Click(object sender, EventArgs e)
{
try
{
if(IsServiceExisted(ServiceName))
{
Console.WriteLine("当前服务程序已经安装,不能重复安装");
return;
}
InstallService(ServiceFilePath);
Console.WriteLine("安装服务 完成");
}
catch (Exception ex)
{
Console.WriteLine("安装服务程序错误:{0}", ex.Message);
}
}
///
/// 卸载服务 点击事件
///
///
///
private void Button_UnloadService_Click(object sender, EventArgs e)
{
try
{
if (!IsServiceExisted(ServiceName))
{
Console.WriteLine("请先安装服务程序:{0}", ServiceName);
return;
}
ServiceStop(ServiceName);
UninstallService(ServiceFilePath);
Console.WriteLine("卸载服务 完成");
}
catch (Exception ex)
{
Console.WriteLine("卸载服务程序错误:{0}", ex.Message);
}
}
///
/// 判断服务程序是否存在
///
/// 服务程序的名字
///
private bool IsServiceExisted(string serviceName)
{
if (string.IsNullOrEmpty(serviceName))
{
Console.WriteLine("参数 serviceName 不能为空");
return false;
}
System.ServiceProcess.ServiceController[] services =
System.ServiceProcess.ServiceController.GetServices();
foreach (var item in services)
{
if (item.ServiceName.ToLower() == serviceName.ToLower())
return true;
}
return false;
}
///
/// 安装服务
///
/// 服务程序的路径
private void InstallService(string servicePath)
{
if (string.IsNullOrEmpty(servicePath))
{
Console.WriteLine("参数 servicePath 不能为空");
return;
}
using (AssemblyInstaller installer = new AssemblyInstaller())
{
installer.UseNewContext = true;
installer.Path = servicePath;
IDictionary savedState = new Hashtable();
installer.Install(savedState);
installer.Commit(savedState);
}
}
///
/// 卸载服务
///
/// 服务程序的路径
private void UninstallService(string servicePath)
{
if (string.IsNullOrEmpty(servicePath))
{
Console.WriteLine("参数 servicePath 不能为空");
return;
}
using (AssemblyInstaller installer = new AssemblyInstaller())
{
installer.UseNewContext = true;
installer.Path = servicePath;
installer.Uninstall(null);
}
}
///
/// 启动服务
///
/// 服务程序的名字
private void ServiceStart(string serviceName)
{
if (string.IsNullOrEmpty(serviceName))
{
Console.WriteLine("参数 serviceName 不能为空");
return;
}
using (System.ServiceProcess.ServiceController control =
new System.ServiceProcess.ServiceController(serviceName))
{
if (control.Status == System.ServiceProcess.ServiceControllerStatus.Stopped)
control.Start();
}
}
///
/// 停止服务
///
/// 服务程序的名字
private void ServiceStop(string serviceName)
{
if (string.IsNullOrEmpty(serviceName))
{
Console.WriteLine("参数 serviceName 不能为空");
return;
}
using (System.ServiceProcess.ServiceController control =
new System.ServiceProcess.ServiceController(serviceName))
{
if (control.Status == System.ServiceProcess.ServiceControllerStatus.Running)
control.Stop();
}
}
}
}
由于启动服务程序需要管理员权限,现在我们添加权限,右键点击项目,添加--> 新建项,选择 应用程序清单文件:
将原有的代码注释掉,下图中的代码复制出来:
点击保存,并将输出类型改为控制台输出
第一次运行,会提示你是否提升权限,点击 使用其他凭据重新启动
运行项目,选择服务程序的路径
点击 安装服务 按钮,控制台输出了一大堆文字,最后可以看到 “安装服务完成” 的打印。
接下来,我们打开服务程序,找到列表中 T 字开头的服务程序,可以看到我们刚刚安装的 TestService1,在说明这里写着 “测试服务程序”,就是上面操作中手动添加进去的。
打开属性看看:
找到服务程序的安装目录,会多两个文件出来
点击按钮 启动服务 按钮
控制台输出:
在服务程序中,可以看到 “正在运行” 的文字,那么启动服务就是成功了。
如果你之前已经打开了服务程序,点击一下刷新按钮就好了
在服务程序目录,会多一个文件夹,打开这个文件夹
在 LogInfo 文件夹中找到当天的日期的日志文件
在浏览器中打开,就能看到代码中输出的日志
点击 停止服务 按钮
控制台输出:
在服务程序列表中,“正在运行” 的状态已经变成了一片空白,那么就是成功了。
我们打开日志文件:
点击 卸载服务 按钮
控制台同样输出了一大堆文字,这里执行会稍微慢点,界面会卡死,执行完成后,在最后一行可以看到 “卸载服务完成” 的打印,那么就是成功了,这时界面的卡死也恢复了正常。(单线程的缘故)
打开服务程序,可以看到,我们安装的 TestService1 服务程序已经没有了
那么这就是服务程序大致的操作了。
源码:点击跳转
如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言
end