Net6.0 编写看门狗程序
程序名称: GateKeeper
功能:本程序可以监视Windows服务程序和Windows进程,一旦发现被监视的服务或进程停止运行,程序会立即程序启动它。不说废话,直接贴代码。

1、主程序:Program.cs
namespace GateKeeper { public class Program { public static async Task Main(string[] args) { IHost host = Host.CreateDefaultBuilder(args) .UseWindowsService() .ConfigureLogging(logging => { logging.ClearProviders(); logging.AddProvider(new LoggerFileProvider("GateKeeper")); }) .ConfigureServices(services => { services.AddHostedService<Worker>(); }) .Build(); await host.RunAsync(); } } }
2、文件日志提供器:LoggerFileProvider.cs
using System.Reflection; namespace GateKeeper { /// <summary> /// 文件日志提供器 /// </summary> public class LoggerFileProvider : ILoggerProvider { private readonly string _appId; public LoggerFileProvider(string appId) { _appId = appId; } public ILogger CreateLogger(string categoryName) { return new Logger(categoryName, _appId); } public void Dispose() { } public class Logger : ILogger { private readonly string _categoryName; private readonly string _appId; private static readonly string logFileFmt = "yyyy-MM-dd"; private static string logDate = DateTime.Now.ToString(logFileFmt); public Logger(string categoryName, string appId) { _categoryName = categoryName; _appId = appId; } public IDisposable BeginScope<TState>(TState state) { return new NoopDisposable(); } private class NoopDisposable : IDisposable { public void Dispose() { } } public bool IsEnabled(LogLevel logLevel) { return false; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) { try { RecordMsg(logLevel, eventId, state, exception, formatter); } catch (Exception ex) { RecordMsg(logLevel, eventId, state, ex, formatter); } } private void RecordMsg<TState>(LogLevel logLevel, EventId eventId, TState? state, Exception? exception, Func<TState, Exception?, string> formatter) { string msg = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff} - [{logLevel.ToSingle()}] - {formatter(state!, exception)}"; msg = msg.Replace("\r", "").Replace("\n", ""); Console.WriteLine(msg); var dirPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "log"); if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } var filePath = Path.Combine(dirPath, "log.txt"); var date = DateTime.Now.ToString(logFileFmt); if (!date.Equals(logDate)) { var backPath = Path.Combine(dirPath, logDate + ".log"); File.Copy(filePath, backPath, true); File.WriteAllText(filePath, ""); logDate = date; } File.AppendAllText(filePath, msg + Environment.NewLine); } } } public static class Externsions { public static string ToSingle(this LogLevel level) { switch (level) { case LogLevel.Critical: return "C"; case LogLevel.Debug: return "D"; case LogLevel.Error: return "E"; case LogLevel.Information: return "I"; case LogLevel.None: return "N"; case LogLevel.Trace: return "T"; case LogLevel.Warning: return "W"; default: return ""; } } } }
3、进程配置信息: ProcessInfo.cs
namespace GateKeeper { public class ProcessInfo { public string? Name { get; set; } public string? Location { get; set; } } }
4、Windows服务控制:WindowsService.cs
using System.ServiceProcess; namespace GateKeeper { [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:验证平台兼容性", Justification = "<挂起>")] public class WindowsService { public static ServiceControllerStatus GetWinServiceStatus(string serviceName) { var sc = new ServiceController(serviceName); return sc.Status; } public static void StopWinService(string serviceName) { var sc = new ServiceController(serviceName); sc.Stop(); } public static void StartWinService(string serviceName) { var sc = new ServiceController(serviceName); sc.Start(); } public static void RefreshWinService(string serviceName) { var sc = new ServiceController(serviceName); sc.Refresh(); } } }
5、服务程序:Worker.cs
using System.Diagnostics; namespace GateKeeper { public class Worker : BackgroundService { private readonly ILogger<Worker> _logger; private readonly IConfiguration _configuration; private bool running = true; public Worker(ILogger<Worker> logger, IConfiguration configuration) { _logger = logger; _configuration = configuration; } public override Task StartAsync(CancellationToken cancellationToken) { running = true; return base.StartAsync(cancellationToken); } public override Task StopAsync(CancellationToken cancellationToken) { running = false; return base.StopAsync(cancellationToken); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await Task.Delay(300, stoppingToken); var services = _configuration.GetSection("Services").Get<List<string>>() ?? new List<string>(); _logger.LogInformation("监视的服务:{msg}", string.Join(",", services)); _ = Task.Run(async () => { while (running) { ServiceDaemon(services); await Task.Delay(int.Parse(_configuration["Interval"])); } _logger.LogInformation("ServiceDaemon exit"); }); var processes = _configuration.GetSection("Processes").Get<List<ProcessInfo>>() ?? new List<ProcessInfo>(); _logger.LogInformation("监视的进程:{msg}", string.Join(",", processes.Select(p => $"{p.Name}|{p.Location}"))); _ = Task.Run(async () => { while (running) { ProcessDeamon(processes); await Task.Delay(int.Parse(_configuration["Interval"])); } _logger.LogInformation("ProcessDeamon exit"); }); _logger.LogInformation("{msg}", $"时间间隔:{_configuration["Interval"]}毫秒"); } private void ServiceDaemon(List<string> services) { foreach (var name in services) { try { if (WindowsService.GetWinServiceStatus(name) == System.ServiceProcess.ServiceControllerStatus.Stopped) { WindowsService.StartWinService(name); _logger.LogInformation("{message}", $"{name}停止,已经重新启动"); } } catch (Exception ex) { _logger.LogWarning("{message}", ex.Message); } } } private void ProcessDeamon(List<ProcessInfo> processes) { foreach (var process in processes) { var processList = Process.GetProcessesByName(process.Name); if (processList.Length == 0) { var info = new ProcessStartInfo { FileName = process.Location, Arguments = "", WindowStyle = ProcessWindowStyle.Minimized }; Process.Start(info); _logger.LogInformation("{msg}", $"{process.Name}停止, 已重新启动"); Task.Delay(4000).Wait(); } Task.Delay(1000).Wait(); } } } }
6、配置文件:AppSettings.json
{ "Logging": { "LogLevel": { "Default": "Debug", "Microsoft.Hosting.Lifetime": "Information" } }, "Interval": 1000, /* 循环的时间间隔(毫秒)*/ "Services": [ "MariaDB" ], /* 监视的服务 */ "Processes": [ { "Name": "EmEditor", /* 监视的进程 */ "Location": "C:\\Users\\Robot\\AppData\\Local\\Programs\\EmEditor\\EmEditor.exe" /* 执行路径 */ } ] }
说明:本程序可以作为控制台程序直接运行, 也可安装为Windows服务运行。
运行效果:


浙公网安备 33010602011771号