目录
免责声明
介绍
解决方案
添加配置设置
添加带有文件夹列表的配置文件
我们的代码
将应用程序转换为Windows服务
创建Windows服务曾经是一个繁琐的过程,但是随着.NET Core 3.0中引入的新工作程序服务框架变得更加容易。本文中的代码主要是为了向读者介绍辅助服务,并说明如何将辅助服务部署为Windows服务,但希望该应用程序本身也具有实际用途。
- 下载源文件-4 KB
我们在此处创建的服务用于从独立配置文件中指定的文件夹列表中删除早于特定日期的文件。该应用程序已经过测试,据我所知它可以在我的环境中运行。我不保证它将在您的环境中完美无缺。在生产环境中使用此功能之前,强烈建议您执行一些其他测试。
介绍在本文中,我将介绍如何在Visual Studio中使用Worker Service模板创建简单的Windows Service。
在引入.NET Core 3.0中的Worker Services之前,您可能会使用.NET Windows Service模板创建Windows服务。我一直认为,使用该模板的经验从来都不是很直观的。您可能会遇到的第一个问题是,如果不实现某些代码黑客,就无法在Visual Studio环境中运行该服务。此外,该模板并没有为您提供使服务按预期运行所需的实际指导。幸运的是,有了.NET 3.0和Worker Services,所有这些都变得更加容易。
解决方案要阅读本文,您需要在您的环境中安装Visual Studio 2019和.NET Core 3.0。
首先,您需要创建一个新项目,并选择下图所示的工作流程模板:
在appsettings.json文件中,我们将需要添加一些配置。一个配置的阈值,说明最大允许年龄的文件之前,我们删除它。让我们将此设置称为NumberOfDaysBeforeDelete。我将此值设置为90天。除此之外,我们需要包含要监视的文件夹列表的独立配置文件的文件路径。我将其称为ConfigurationFilePath设置,并将其指向我的c:\temp文件夹中的某个位置。需要最后一个设置来配置此服务将执行我们的自定义代码的时间间隔。我称这个设置为RunIntervallInHours,然后将值设置为12小时,这意味着该服务每天两次检查配置文件中每个文件夹的内容,并删除最后写入日期超过90天的所有文件。这三个配置设置被分组为appsettings.json文件中的一个节点,我称之为“App.Configurations”,请参见以下内容:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"App.Configurations": {
"ConfigurationFilePath": "C:\\Temp\\CleanUpFolders\\CleanUpConfigurations.config",
"NumberOfDaysBeforeDelete": "10",
"RunIntervallInHours": "12"
}
}
请注意,您的项目中同时有一个“appsetttings.json”文件和一个“appsettings.development.json”文件。在运行时使用哪个appsettings.json文件取决于您的环境设置。从Visual Studio运行此服务时,默认情况下将使用文件Properties/launchSettings.json中配置的开发设置。
我在c:\Temp\CleauUpFoders\中创建一个名为CleanUpConfigurations.config的文件,并将以下两行放入其中:
C:\Temp\CleanUpFolders\Folder1
C:\Temp\CleanUpFolders\Folder2
我还在同一位置创建文件夹“Folder1”和“Folder2”。
在新创建的解决方案中,最初需要我们关注两个文件,用于启动应用程序的program.cs和包含该解决方案的自定义代码的worker.cs。在program.cs文件中,您将找到用于设置主机环境的代码。为了便于将此应用程序作为Windows服务运行,您需要添加以下NuGet软件包。
Install-Package Microsoft.Extensions.Hosting.WindowsServices
安装该软件包后,您可以在Host.CreateDefaultBuilder(args)后面添加行.UseWindowsService(),以便最终在program.cs文件中添加以下内容。
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService();
});
}
在worker.cs文件中,我们首先将IServiceScopeFactory实例插入构造函数。这将用于访问appsettings配置文件。
public Worker(ILogger logger, IServiceScopeFactory serviceScopeFactory)
{
_logger = logger;
_serviceScopeFactory = serviceScopeFactory;
}
为了确保每次启动服务时都读取配置,我重写了该方法StartAsync并在此处检索我的应用程序配置:
public override Task StartAsync(CancellationToken cancellationToken)
{
_configuration = _serviceScopeFactory.CreateScope().
ServiceProvider.GetRequiredService();
_numberOfDaysBeforeDelete = int.Parse(_configuration
["App.Configurations:NumberOfDaysBeforeDelete"]);
_runIntervallInHours = int.Parse(_configuration
["App.Configurations:RunIntervallInHours"]);
_folderPaths = File.ReadAllLines(_configuration
["App.Configurations:ConfigurationFilePath"]).Select(x => x.Trim()).ToList();
return base.StartAsync(cancellationToken);
}
请注意,我是如何从ConfigurationFilePath设置中所述文件中读取所有行并将其放入list _folderPaths的。
在Worker类中声明以下变量:
private IList _folderPaths;
private int _numberOfDaysBeforeDelete;
private int _runIntervallInHours;
从我们的配置文件中检索文件夹并删除所有90天以上的文件的代码将放置在该ExecuteAsync方法中。ExecuteAsync以CancellationToken作为参数。CancellationToken非常重要,因为它将用于识别服务何时停止。发生这种情况时,属性IsCancellationRequested将设置为true。因此,我们ExecuteAsync代码的第一行是:
while (!stoppingToken.IsCancellationRequested)
我将在此方法中进一步检查IsCancellationRequested,以确保在收到取消请求时尽快停止执行。用于获取文件天数x天以上并删除它们的代码分为两行:
var files = Directory.GetFiles(path).Select(file => new FileInfo(file)).Where
(file => file.LastWriteTime < DateTime.Now.AddDays(-1* _numberOfDaysBeforeDelete)).ToList();
// Delete found files
files.ForEach(file => file.Delete());
在关闭while循环之前,我延迟了一下。由于我们的setting _runIntervallInHours时间设置为12小时,因此该代码将使服务停止12小时,然后再继续执行。
await Task.Delay(TimeSpan.FromHours(_runIntervallInHours), stoppingToken);
请注意,此处使用了取消标记,这会导致Windows服务停止时取消等待过程。
该ExecuteAsync方法的完整代码如下所示:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
foreach (var path in _folderPaths)
{
if (!stoppingToken.IsCancellationRequested)
{
// Get old files
var files = Directory.GetFiles(path).Select
(file => new FileInfo(file)).Where
(file => file.LastWriteTime < DateTime.Now.AddDays
(-1* _numberOfDaysBeforeDelete)).ToList();
// Delete found files
files.ForEach(file => file.Delete());
}
}
await Task.Delay(TimeSpan.FromHours(_runIntervallInHours), stoppingToken);
}
}
那就是我们需要的所有代码。您只需按F5键,然后直接从Visual Studio运行该应用程序,然后看它是否有效。
现在继续并发布应用程序。
到文件夹:
以管理员身份打开PowerShell终端并运行以下命令:
sc.exe create FolderCleanUpService binpath= "C:\Apps\FolderCleanUpService.exe" start= auto
这会将服务安装在Windows计算机上。
您可以将服务放置在所需的任何位置,我在这里选择将其放置在C盘的Apps文件夹中。我使用该标志来确保Windows启动时自动启动该服务。要设置服务描述,您需要执行第二条命令:start=auto
sc.exe description "FolderCleanUpService"
"This service monitors and deletes files older than 90 days"
按(Window + R)并运行命令services.msc,然后您应该会看到所有服务的列表,并且在该列表中您应该能够看到该FolderCleanUpService服务。您需要首次手动启动它,但是由于启动类型设置为自动,因此它将在重新启动后自动自行启动。
您可以使用以下命令删除服务:
sc.exe delete "FolderCleanUpService"