开机启动和windows服务的区别
- 将应用程序或者脚本等文件设置为开机启动时,需要用户登录系统时才回去执行,这可能还需要用户输入开机密码或者赋予程序和脚本的管理员执行权限等额外操作。
windows
服务则不同,它是随系统一起启动的,我们不需要额外的用户操作,再执行一些自动化操作时,注册服务显然比开机启动项更占优势。
服务注册
在windows
系统中,自带了SC
服务管理程序,它是一个服务控制管理器和服务进行通信的命令行程序。
使用sc create
命令来创建一个服务,示例命令如下:
#binPath指定应用程序路径,start参数指定启动方式,displayname指定服务显示的名称
sc create MyService binPath="M:\Projects\Redir\Test\Test\bin\Debug\net6.0\Test.exe" start=auto displayname="CocoService"
添加服务描述
使用sc description
命令为注册服务添加描述,示例命令如下:
sc description MyService "CocoService描述"
启动服务
使用sc start
命令启动服务,示例命令如下:
🍕可以看到服务启动报错,为什么呢,我们先看一下Test.exe
这个程序是干嘛的,代码如下:
while (true)
{
//每隔十秒将当前时间写入到文件中
Thread.Sleep(1000 * 10);
File.AppendAllText("time.txt", DateTime.Now.ToLocalTime().ToString());
}
代码很简单就是一个很普通的控制台程序,每隔十秒将当前时间写入到名为time.txt
的文件中,看了一下windows
服务的应用程序日志,也有系统错误日志,但未指出错误原因;网上查询了好久,终于在一个评论区看到一条回复:sc程序无法将普通应用程序或者批处理文件注册为系统服务,windows服务有特有的编写方式。
正确姿势
使用Work Service
项目来编写windows
服务,首先创建一个项目
程序入口文件内容如下:
using MyService;
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services => { services.AddHostedService<Worker>(); })
.Build();
await host.RunAsync();
和Asp.NetCore
项目非常相似,创建一个宿主主机来托管我们的程序,重点来了,要创建windows
服务我们需要依赖一个NuGet
包
它提供了IHostBuilder
的一个扩展方法,让我们将用程序注册为windows
服务,看一下默认的Worker
服务
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
它继承了BackgroundService
类,然后重写了ExecuteAsync
方法,我们要后台运行的代码就放到这个方法中由托管主机来调用,书接上文,编写一段每隔10秒将当前时间写入到文档中的方法
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
File.AppendAllText(AppContext.BaseDirectory + "time.txt", DateTime.Now.ToLocalTime() + "\n");
await Task.Delay(1000, stoppingToken);
}
}
修改入口程序
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services => { services.AddHostedService<Worker>(); })
.UseWindowsService(options =>
{
options.ServiceName = "MyService";
} )
.Build();
await host.RunAsync();
调用UseWindowsService
方法并声明服务名称。OK,程序编写完毕,我们将项目发布,然后再使用SC
来创建windows
服务
需要注意的是使SC
创建服务时,服务名必须和UseWindowsService
方法指定的服务名一致,=
后面必须接一个空格。接下来启动服务
再看下服务面板
验证一下程序运行是否正常,查看time.txt
文件内容