一、开发环境
系统:Win10、SentOs7
工具:VisualStudio2019,-V16.73
框架:.NetCore3.1
服务项目基础搭建:
创建新项目选择WorkerService下一步
填好名称选好项目路径位置点击创建
点击创建
添加NuGet包:
Microsoft.Extensions.Hosting.Systemd(部署linux系统)
Microsoft.Extensions.Hosting.WindowsServices(部署window系统)
Program.cs类改写原方法
//public static IHostBuilder CreateHostBuilder(string[] args) =>
// Host.CreateDefaultBuilder(args)
// .ConfigureServices((hostContext, services) =>
// {
// services.AddHostedService<Worker>();
// });
public static IHostBuilder CreateHostBuilder(string[] args)
{
//是否是win平台
bool isWin = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
Console.WriteLine($"win:{isWin}");
if (isWin)
{
return Host.CreateDefaultBuilder(args)
.UseWindowsService()//win
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
return Host.CreateDefaultBuilder(args)
.UseSystemd()//linux
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
Worker.cs类:在Worker中重写继承类BackgroundService的StartAsync、ExecuteAsync、StopAsync方法,异步线程防阻塞,添加日志方法。
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public string dtNow = string.Format("{0:yyyyMMdd}", DateTime.Now);
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
public override async Task StartAsync(CancellationToken cancellationToken)
{
var time = string.Format("{0:HH:mm:ss}", DateTime.Now);
_logger.LogInformation("start service system time========: {time}", time);
var fileName = "Start_Service" + dtNow + ".txt";
LogTxt("start service", fileName);
await base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var time = string.Format("{0:HH:mm:ss}", DateTime.Now);
_logger.LogInformation("system time========: {time}", time);
//IConfiguration configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
//var runTime = configuration.GetSection("AppSettings")["runtime"];
//特定时间执行
if (time == "01:00:00")
{
_logger.LogInformation("start执行同步数据任务");
//异步线程防阻塞
await Task.WhenAny(DataProcessing(stoppingToken));
GC.Collect();
}
//延时执行-毫秒
await Task.Delay(1000, stoppingToken);
}
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
var fileName = "Stop_Service" + dtNow + ".txt";
LogTxt("stop service", fileName);
await base.StartAsync(cancellationToken);
}
/// <summary>
/// 数据处理
/// </summary>
/// <param name="stoppingToken"></param>
/// <returns></returns>
public Task DataProcessing(CancellationToken stoppingToken)
{
try
{
return Task.Run(() =>
{
var fileName = "Log_" + dtNow + ".txt";
if (stoppingToken.IsCancellationRequested)
{
return;
}else{
//服务处理过程
}
});
}
catch (Exception ex)
{
var fileName = "ERROR_" + dtNow + ".txt";
LogTxt("程序错误:" + ex.Message, fileName);
throw;
}
}
/// <summary>
/// 日志记录
/// </summary>
/// <param name="txt">日志内容</param>
/// <param name="fileName">文件名</param>
public static void LogTxt(string txt, string fileName)
{
string filePath = "/home/username/WorkerS/log";//绝对路径:"C:\\WorkerS\\log"--"linux:/home/username/WorkerS/log"--//相对路径:"log"
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
var dataTime = string.Format("{0:yyyy-MM-dd HH:mm:ss}", DateTime.Now);
fileName = filePath + "/" + fileName;
StreamWriter sw = null;
if (File.Exists(fileName))
{
sw = new StreamWriter(fileName, true, Encoding.GetEncoding("UTF-8"));
}
else
{
sw = new StreamWriter(fileName, false, Encoding.GetEncoding("UTF-8"));
}
StringBuilder dataRow = new StringBuilder("");
dataRow.Append(dataTime + ":" + txt);
sw.WriteLine(dataRow.ToString());
sw.Close();
}
}
发布服务
vs2019内控制台命令:
dotnet publish -c Release -o C:\WorkerS
鼠标右击项目发布:
win10创建、管理服务:
需.NetCoreRunTime详见:
https://docs.microsoft.com/zh-cn/dotnet/core/install/windows?tabs=net50
cmd(管理员权限打开)
创建服务:sc.exe create ServiceName binPath=C:\WorkerS\TestWorkerService.exe
查询服务:sc.exe query ServiceName
启动服务:sc.exe start ServiceName
停止服务:sc.exe stop ServiceName
删除服务:sc.exe delete ServiceName
添加服务描述:sc.exe description ServiceName "描述"
改变服务的启动方式 手动/自动/禁用:sc.exe config ServiceName start= demand/auto/disabled
Linux部署服务(下面是我在sentos7上部署相关操作):
首先需要安装.NetCore SDK:
具体见官方文档说明:https://docs.microsoft.com/zh-cn/dotnet/core/install/linux-centos
通过systemd守护进程部署服务:创建ServiceName.service文件到 /usr/lib/systemd/system/目录
cd /usr/lib/systemd/system/
sudo touch ServiceName.service
vim打开文件输入内容:
[Unit]
Description=Test Service Daemon #描述
After=network-online.target
[Service]
Type=simple #定义启动类型()
WorkingDirectory=/home/username/WorkerS/ #指定项目路径
ExecStart=/usr/bin/dotnet TestWorkerService.dll #启动命令
Restart=always #服务崩溃重启 #on-failure =非正常退出时重启
User=root
[Install]
WantedBy=multi-user.target
重新加载配置文件:
sudo systemctl daemon-reload
启动:
sudo systemctl start ServiceName
停止:
sudo systemctl stop ServiceName
查看服务状态:
sudo systemctl status ServiceName
开机自启:
sudo systemctl enable ServiceName
关闭自启:
sudo systemctl disable ServiceName
查看服务日志:
sudo journalctl -u ServiceName
清理日志:
sudo journalctl --vacuum-time=1h
列出所有的服务:
systemctl list-units --type=service