zoukankan      html  css  js  c++  java
  • 使用WorkService创建定时任务

    引用:

    .NET 中的 Worker Service 入门介绍 - 技术译民 - 博客园 (cnblogs.com)

    在 ASP.NET Core和Worker Service中使用Quartz.Net - 码农译站 - 博客园 (cnblogs.com)

    新建 Worker Services

    新建 Worker Services

    添加Nlog

    手动或使用NuGet在csproj中添加依赖项

    • 安装最新版本:
    • NLog.Web.AspNetCore 4.9+
    • 如有可能,更新NLog软件包

    创建nlog.config文件。

    在项目的根目录中创建nlog.config(全部小写)文件。
    我们使用以下示例:

    <?xml version="1.0" encoding="utf-8" ?>
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    
      <!-- enable asp.net core layout renderers -->
      <extensions>
        <add assembly="NLog.Web.AspNetCore"/>
      </extensions>
    
      <!-- the targets to write to -->
      <targets>
        <!--写入文件-->
        <target
         xsi:type="File"
         name="DebugFile"
         fileName="Logs\Debug\${shortdate}.log"
         layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}----------------------------------------------------------------${newline}" >
        </target>
        <target
          xsi:type="File"
          name="InfoFile"
          fileName="Logs\Info\${shortdate}.log"
          layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}----------------------------------------------------------------${newline}" >
        </target>
        <target
          xsi:type="File"
          name="ErrorFile"
          fileName="Logs\Error\${shortdate}.log"
          layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}异常信息:${exception:format=tostring}${newline}----------------------------------------------------------------${newline}" >
        </target>
      </targets>
    
      <!-- rules to map from logger name to target -->
      <rules>
        <!--Skip non-critical Microsoft logs and so log only own logs-->
        <logger name="Microsoft.*" maxlevel="Info" final="true" />
        <logger name="*" minlevel="Debug" maxLevel="Debug" writeTo="DebugFile" />
        <logger name="*" minlevel="Info" maxLevel="Info" writeTo="InfoFile" />
        <logger name="*" minlevel="Error" maxLevel="Error" writeTo="ErrorFile" />
      </rules>
    </nlog>
    

    注意:日志生成的文件在bin目录下

    配置文件的更多详细信息在这里

    请注意,如果删除所有其他LoggingProviders(如控制台)并且仅使用NLog,则可能必须特别注意Hosting Lifetime Startup Messages。因为这可能导致托管环境(Visual Studio / Docker / Azure容器)看不到启动的应用程序。

    启用复制到bin文件夹

    • .csproj手动编辑文件并添加:
      <ItemGroup>
          <Content Update="nlog.config" CopyToOutputDirectory="PreserveNewest" />
      </ItemGroup>
      

    修改 program.cs

    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using System;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Logging;
    using NLog.Web;
    
    namespace DemoWorkerService
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
                try
                {
                    logger.Debug("init main");
                    CreateHostBuilder(args).Build().Run();
                }
                catch (Exception exception)
                {
                    //NLog: catch setup errors
                    logger.Error(exception, "Stopped program because of exception");
                    throw;
                }
                finally
                {
                    // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
                    NLog.LogManager.Shutdown();
                }
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .ConfigureServices((hostContext, services) =>
                    {
                        services.AddHostedService<Worker>();
                    }).ConfigureLogging(logging =>
                    {
                        logging.ClearProviders();
                        logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                    })
    .UseNLog();  // NLog: Setup NLog for Dependency injection;
        }
    }
    
    

    配置 appsettings.json

    {
      "Logging": {
        "IncludeScopes": false,
        "LogLevel": {
          "Default": "Trace",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*"
    }
    

    写日志

    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace DemoWorkerService
    {
        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);
                }
            }
        }
    }
    
    

    运行后日志不在控制台显示

    注意:日志生成的文件在bin目录下

    使用Quartz.Net

    安装Quartz.Net

    手动或使用NuGet在csproj中添加依赖项

    • 安装最新版本:

      Microsoft.Extensions.Hosting 5.0+

      Quartz.Extensions.Hosting 3.3.3+

    • 如有可能,更新Quartz软件包

    使用Quartz.Net

    • 创建ServiceCollectionQuartzConfiguratorExtensions.cs拓展文件

      using Microsoft.Extensions.Configuration;
      using Quartz;
      using System;
      using System.Collections.Generic;
      using System.Text;
      
      namespace DemoWorkerService
      {
          public static class ServiceCollectionQuartzConfiguratorExtensions
          {
              public static void AddJobAndTrigger<T>(
              this IServiceCollectionQuartzConfigurator quartz,
              IConfiguration config)
              where T : IJob
              {
                  // Use the name of the IJob as the appsettings.json key
                  string jobName = typeof(T).Name;
      
                  // Try and load the schedule from configuration
                  var configKey = $"Quartz:{jobName}";
                  var cronSchedule = config[configKey];
      
                  // Some minor validation
                  if (string.IsNullOrEmpty(cronSchedule))
                  {
                      throw new Exception($"No Quartz.NET Cron schedule found for job in configuration at {configKey}");
                  }
      
                  // register the job as before
                  var jobKey = new JobKey(jobName);
                  quartz.AddJob<T>(opts => opts.WithIdentity(jobKey));
      
                  quartz.AddTrigger(opts => opts
                      .ForJob(jobKey)
                      .WithIdentity(jobName + "-trigger")
                      .WithCronSchedule(cronSchedule)); // use the schedule from configuration
              }
          }
      }
      
      
    • 创建HelloWorldJob.cs任务文件

      using Microsoft.Extensions.Logging;
      using Quartz;
      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace DemoWorkerService.Jobs
      {
          [DisallowConcurrentExecution]
          public class HelloWorldJob : IJob
          {
              private readonly ILogger<HelloWorldJob> _logger;
              public HelloWorldJob(ILogger<HelloWorldJob> logger)
              {
                  _logger = logger;
              }
      
              public Task Execute(IJobExecutionContext context)
              {
                  _logger.LogInformation("Hello world!");
                  return Task.CompletedTask;
              }
          }
      }
      
      
    • 添加服务

       public static IHostBuilder CreateHostBuilder(string[] args) =>
                  Host.CreateDefaultBuilder(args)
                      .UseWindowsService()
                      .ConfigureServices((hostContext, services) =>
                      {
                          // Add the required Quartz.NET services
                          services.AddQuartz(q =>
                          {
                              q.UseMicrosoftDependencyInjectionJobFactory();
      		
      						// Register the job, loading the schedule from configuration
                              q.AddJobAndTrigger<HelloWorldJob>(hostContext.Configuration);
                          });
      
                          // WaitForJobsToComplete:此设置确保当请求关闭时,Quartz.NET在退出之前等待作业优雅地结束。
                          services.AddQuartzHostedService(
                              q => q.WaitForJobsToComplete = true);
      
                          // other config
                      }).ConfigureLogging(logging =>
                      {
                          logging.ClearProviders();
                          logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                      })
                      .UseNLog();  // NLog: Setup NLog for Dependency injection;
      

      文件将不会打印再控制器台中

    • 添加配置文件再appsettings.json

      "Quartz": {
      	"HelloWorldJob": "0/5 * * * * ?"
      }
      

    添加 Windows Services 依赖

    为了作为 Windows 服务运行,我们需要我们的 Worker 监听来自 ServiceBase 的启动和停止信号,ServiceBase 是将 Windows 服务系统公开给 .NET 应用程序的 .NET 类型。为此,我们需要添加 Microsoft.Extensions.Hosting.WindowsServices NuGet 包:

    dotnet add package Microsoft.Extensions.Hosting.WindowsServices
    

    然后修改 Program.cs 中的 CreateHostBuilder 方法,添加 UseWindowsService 方法调用:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .UseWindowsService()
                    .ConfigureServices((hostContext, services) =>
                    {
                        
                    }).ConfigureLogging(logging =>
                    {
                        logging.ClearProviders();
                        logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                    })
                    .UseNLog();  // NLog: Setup NLog for Dependency injection;
    

    发布程序

    dotnet publish -c Release -r win-x64 -o D:\DemoWorkerService
    

    D:\DemoWorkerService为发布后的地址

    创建并运行任务

    当我们使用 sc.exe 实用工具管理服务时,必须以管理员身份运行 Windows 命令提示符,否则会执行失败。

    • 安装服务

      sc create 我的服务名称 binPath= "D:\DemoWorkerService\DemoWorkerService.exe" start= auto displayname= "服务描述"
      

      1、每个命令行选项 (参数) 必须包含等号作为选项名称的一部分。
      2、选项与其值之间必须有一个空格(例如,type= own),如果遗漏了空格,操作将失败。

      sc create
      
      描述:
              在注册表和服务数据库中创建服务项。
      用法:
              sc <server> create [service name] [binPath= ] <option1> <option2>...
      
      选项:
      注意: 选项名称包括等号。
            等号和值之间需要一个空格。
       type= <own|share|interact|kernel|filesys|rec|userown|usershare>
             (默认 = own)
       start= <boot|system|auto|demand|disabled|delayed-auto>
             (默认 = demand)
       error= <normal|severe|critical|ignore>
             (默认 = normal)
       binPath= <.exe 文件的 BinaryPathName>
       group= <LoadOrderGroup>
       tag= <yes|no>
       depend= <依存关系(以 / (斜杠)分隔)>
       obj= <AccountName|ObjectName>
             (默认= LocalSystem)
       DisplayName= <显示名称>
       password= <密码>
      
    • 设置服务描述

      sc description
      描述:
              设置服务的描述字符串。
      用法:
              sc <server> description [service name] [description]
      
      sc description 我的服务名称 "服务描述"
      
    • 启动服务

      sc start 我的服务名称
      
    • 停止服务

      sc stop 我的服务名称
      
    • 删除服务

      sc delete 我的服务名称
      
  • 相关阅读:
    推荐网址:Response.WriteFile Cannot Download a Large File
    为什么是 My?
    Fox开发杂谈
    DCOM配置为匿名访问
    连接到运行 Windows 98 的计算机
    OO面向对象以后是什么
    Com+的未来是什么?
    fox 表单和类库的加密及修复
    来自 COM 经验的八个教训
    VFP的加密问题
  • 原文地址:https://www.cnblogs.com/qs315/p/15593849.html
Copyright © 2011-2022 走看看