C# Windows 服务程序的开发

目录

一、概述

二、新建服务程序

三、安装前的准备

四、启动、停止,安装、卸载

五、测试

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 的

C# Windows 服务程序的开发_第1张图片

或者直接搜索“服务”二字

C# Windows 服务程序的开发_第2张图片

这里就直接用默认的名字吧

C# Windows 服务程序的开发_第3张图片

创建完成后的界面

C# Windows 服务程序的开发_第4张图片

选中 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

C# Windows 服务程序的开发_第5张图片

新建一个类 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 文件设置成:如果较新则复制

C# Windows 服务程序的开发_第6张图片

服务程序并不能直接启动,安装服务程序需要固定的流程,接下来是安装服务程序的相关内容。

三、安装前的准备

双击 Service1.cs 文件

C# Windows 服务程序的开发_第7张图片

就打开了 Service1 的设计界面,接着点击 添加安装界面

C# Windows 服务程序的开发_第8张图片

这时候会自动生成一个 ProjectInstaller 的文件

C# Windows 服务程序的开发_第9张图片

点击 serviceInstaller1 查看属性

C# Windows 服务程序的开发_第10张图片

Windows 服务程序主要用到的有几个属性:

Description                服务的说明

ServiceName             服务的名字

StartType                   服务的启动类型

这几个属性可以参考下图:

C# Windows 服务程序的开发_第11张图片

这里我就随便设置下:

C# Windows 服务程序的开发_第12张图片

再点击 serviceProcessInstaller1,查看属性

C# Windows 服务程序的开发_第13张图片

将 Account 设置为 LocalService

C# Windows 服务程序的开发_第14张图片

以上操作完成后,将项目保存,生成程序。

Windows 服务程序一般用控制台进行安装和卸载的,但控制台用起来不是特别方便,这里我就用 Winform 写一个对应的程序好了。

四、启动、停止,安装、卸载

新一个 Winform 项目,名字叫 ServiceControl, 主要用来操作服务程序的启动、停止,安装、卸载。

创建项目完成后,需要添加一个 dll,名字叫 System.ServiceProcess,一般默认情况下在创建项目时是不会主动添加这个 dll 的,在引用管理器中选择程序集,然后搜索,找到之后添加到项目中就好了。

C# Windows 服务程序的开发_第15张图片

Winform 界面如下:

C# Windows 服务程序的开发_第16张图片

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();
            }
        }
    }
}

由于启动服务程序需要管理员权限,现在我们添加权限,右键点击项目,添加--> 新建项,选择 应用程序清单文件:

C# Windows 服务程序的开发_第17张图片

将原有的代码注释掉,下图中的代码复制出来:

C# Windows 服务程序的开发_第18张图片

点击保存,并将输出类型改为控制台输出

C# Windows 服务程序的开发_第19张图片

第一次运行,会提示你是否提升权限,点击 使用其他凭据重新启动

C# Windows 服务程序的开发_第20张图片

五、测试

1.安装项目

运行项目,选择服务程序的路径

C# Windows 服务程序的开发_第21张图片

点击 安装服务 按钮,控制台输出了一大堆文字,最后可以看到 “安装服务完成” 的打印。

C# Windows 服务程序的开发_第22张图片

接下来,我们打开服务程序,找到列表中 T 字开头的服务程序,可以看到我们刚刚安装的  TestService1,在说明这里写着 “测试服务程序”,就是上面操作中手动添加进去的。

C# Windows 服务程序的开发_第23张图片

打开属性看看:

C# Windows 服务程序的开发_第24张图片

找到服务程序的安装目录,会多两个文件出来

C# Windows 服务程序的开发_第25张图片

2.启动项目

 点击按钮 启动服务 按钮

C# Windows 服务程序的开发_第26张图片

控制台输出:

在服务程序中,可以看到 “正在运行” 的文字,那么启动服务就是成功了。

C# Windows 服务程序的开发_第27张图片

如果你之前已经打开了服务程序,点击一下刷新按钮就好了

C# Windows 服务程序的开发_第28张图片

在服务程序目录,会多一个文件夹,打开这个文件夹

C# Windows 服务程序的开发_第29张图片

在 LogInfo 文件夹中找到当天的日期的日志文件

C# Windows 服务程序的开发_第30张图片

在浏览器中打开,就能看到代码中输出的日志

C# Windows 服务程序的开发_第31张图片

3.停止项目

点击 停止服务 按钮

C# Windows 服务程序的开发_第32张图片

控制台输出:

C# Windows 服务程序的开发_第33张图片

在服务程序列表中,“正在运行” 的状态已经变成了一片空白,那么就是成功了。

C# Windows 服务程序的开发_第34张图片

我们打开日志文件:

C# Windows 服务程序的开发_第35张图片

4.卸载项目

点击 卸载服务 按钮

C# Windows 服务程序的开发_第36张图片

控制台同样输出了一大堆文字,这里执行会稍微慢点,界面会卡死,执行完成后,在最后一行可以看到 “卸载服务完成” 的打印,那么就是成功了,这时界面的卡死也恢复了正常。(单线程的缘故)

C# Windows 服务程序的开发_第37张图片

打开服务程序,可以看到,我们安装的  TestService1 服务程序已经没有了

C# Windows 服务程序的开发_第38张图片

那么这就是服务程序大致的操作了。

源码:点击跳转

结束

如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言

end

你可能感兴趣的:(C#,c#)