Quartz.Net+Microsoft.Extensions.Hosting创建服务

5 篇文章 0 订阅

1.首先准备Nuget包:

Microsoft.Extensions.Hosting.WindowsServices

Microsoft.Extensions.Logging.Log4Net.AspNetCore

Quartz.Extensions.Hosting

Quartz.Plugins

Microsoft.Extensions.Http.Polly 如果需要用HttpClient

2.上代码

2.1 main代码

static async Task Main()
{
               var baseDir = AppDomain.CurrentDomain.BaseDirectory;
#region 注册DI注入

                var host = Host.CreateDefaultBuilder()
                    .ConfigureHostConfiguration(configurationBuilder =>
                    {
                        //This is to do some basic host configuration and should only add 2 sources
                        configurationBuilder.SetBasePath(baseDir);
                        configurationBuilder.AddEnvironmentVariables(prefix: "ASPNETCORE_");
#if DEBUG
                        Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
#endif
                    })
                    .ConfigureAppConfiguration((_context, _builder) =>
                    {
                        var env = _context.HostingEnvironment;
                        _builder.AddJsonFile("appsettings.json", false, true)
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true);
                    })
                    .ConfigureServices((context, _services) =>
                    {
                        ConfigureServices(context.Configuration, _services);
                    })
                    .ConfigureLogging(logging =>
                    {
                        logging.ClearProviders();
                        通过config文件实现
                        //logging.SetMinimumLevel(LogLevel.Information);
                        logging.AddLog4Net();
                    })
                    .UseWindowsService()
                    .Build();

                await host.RunAsync();//启动主机
}

2.2 配置服务

/// <summary>
        /// 配置服务
        /// </summary>
        /// <param name="configuration"></param>
        /// <param name="services"></param>
        private static void ConfigureServices(IConfiguration config, IServiceCollection services)
        {
            configuration = config;
            //var loglevel = configration.GetValue<string>("Logging:LogLevel:System.Net.Http.HttpClient");

            //监控平台Api
            services.AddSingleton<IMonitorLogApiService, MonitorLogApiService>();
            ///自定义HttpMessageHandler
            services.AddScoped<LogErrorHttpMsgHandler>();
            //<IMonitorLogApiService, MonitorLogApiService> 拿到的httplient 是新的实例
            services.AddHttpClient("MonitorLogApi", client =>
            {
                var _WXKFBaseUrl = config.GetValue<string>("MonitorLogApi:MonitorLogApiBaseUrl");
                var WXKFBaseUrl = _WXKFBaseUrl ?? "https://status-test.gileadchina.cn/api/services/MonitorLog/";
                client.BaseAddress = new Uri(WXKFBaseUrl);
                //默认接收
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.Timeout = TimeSpan.FromSeconds(100);//100秒超时
            })
            .ConfigurePrimaryHttpMessageHandler(_ =>
            {
                HttpClientHandler handler = new HttpClientHandler();
                handler.AllowAutoRedirect = true;
                return handler;
            })
            .SetHandlerLifetime(TimeSpan.FromHours(12))
            .AddHttpMessageHandler<LogErrorHttpMsgHandler>();

            #region Quartz.Net

            // base configuration from appsettings.json
            services.Configure<QuartzOptions>(configuration.GetSection("Quartz"));
            services.AddQuartz(qz =>
            {
                // as of 3.3.2 this also injects scoped services (like EF DbContext) without problems
                qz.UseMicrosoftDependencyInjectionJobFactory();
                // or for scoped service support like EF Core DbContext
                // q.UseMicrosoftDependencyInjectionScopedJobFactory();
                // these are the defaults
                qz.UseSimpleTypeLoader();
                qz.UseInMemoryStore();
                qz.UseDefaultThreadPool(tp =>
                {
                    tp.MaxConcurrency = 10;
                });
                //使用配置文件
                //qz.UseXmlSchedulingConfiguration(x => x.Files = new string[] {
                //    "quartz_jobs.xml"
                //});
                #region 手动添加Job

                //                qz.ScheduleJob<HospitalTopList2BusinessJob>(trigger =>
                //                {
                //                    string time = System.Configuration.ConfigurationManager.AppSettings["AutoSendHospitalTopList2BusinessJobTriggerTime"].ToString();
                //#if DEBUG
                //                    time = "0 */1 * * * ?";//每分钟执行一次
                //#endif
                //                    trigger
                //                     .WithIdentity("发送进销存Dail报表,每time执行一次", "AutoSendHospitalTopList2BusinessJobGroup")
                //                     .WithCronSchedule(time)
                //                     .StartNow();
                //                }, jobdtl =>
                //                {
                //                    jobdtl.WithIdentity("AutoSendHospitalTopList2BusinessJob", "AutoSendHospitalTopList2BusinessJobGroup");
                //                });
                //                qz.ScheduleJob<AutoSendSalesDailyReportJob>(trigger =>
                //                {
                //                    string time = System.Configuration.ConfigurationManager.AppSettings["AutoSendSalesDailyReportJobTriggerTime"].ToString();
                //#if DEBUG
                //                    time = "0 */1 * * * ?";//每分钟执行一次
                //#endif
                //                    trigger
                //                     .WithIdentity("发送进销存Dail报表,每time执行一次", "AutoSendSalesDailyReportJobGroup")
                //                     .WithCronSchedule(time)
                //                     .StartNow();
                //                }, jobdtl =>
                //                {
                //                    jobdtl.WithIdentity("AutoSendSalesDailyReportJob", "AutoSendSalesDailyReportJobGroup");
                //                });

                #endregion
            });
            services.AddQuartzHostedService(qz =>
            {
                // when shutting down we want jobs to complete gracefully
                qz.WaitForJobsToComplete = true;
            });

            services.AddScoped<AutoSendSalesDailyReportJobTask>();
            //services.AddHostedService<BackgroundJobService>();

            #endregion

        }

2.3 appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information", //Trace = 0, Debug = 1, Information = 2, Warning = 3, Error = 4, Critical = 5, and None = 6.
      "Microsoft.AspNetCore": "Warning",
      "System.Net.Http.HttpClient.*": "Warning" //httpclient日志等级
      //"System.Net.Http.HttpClient.MonitorLogApi.LogicalHandler": "Warning",
      //"System.Net.Http.HttpClient.MonitorLogApi.ClientHandler": "Warning"
    }
  },
  "MonitorLogApi": { //监控平台
    "MonitorLogApiBaseUrl": "https://aaa.cn/api/services/MonitorLog/"
  },
  "Quartz": {
    "schedName": "Report2Mail",
    "quartz.scheduler.instanceId": "Report2MailScheduler",
    "quartz.scheduler.instanceName": "Quartz Hosting Report Scheduler",
    "quartz.threadPool.type": "Quartz Hosting Report Scheduler",
    "quartz.threadPool.threadCount": 5,
    "quartz.threadPool.threadPriority": "Normal",
    "quartz.jobStore.type": "Quartz.Simpl.RAMJobStore, Quartz",
    "quartz.jobStore.misfireThreshold": 6000,
    "quartz.plugin.jobInitializer.type": "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins",
    "quartz.plugin.jobInitializer.fileNames": "quartz_jobs.xml",
    "quartz.plugin.jobInitializer.failOnFileNotFound": true
  }
}

2.4 job配置文件

<!-- This file contains job definitions in schema version 2.0 format -->
<job-scheduling-data version="2.0" xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <processing-directives>
    <overwrite-existing-data>true</overwrite-existing-data>
  </processing-directives>
  <schedule>
    <job>
      <!--作业名称,同一个 group 中作业名称不能相同-->
      <name>List2BusinessJob</name>
      <!--作业分组名称,表示该作业所属分组-->
      <group>jGP_List2BusinessJob</group>
      <!--描述-->
      <description>定时发送 </description>
      <!--指定作业将调用的作业实现类,格式为:命名空间.类名,程序集名称-->
      <job-type>MailJob.Jobs.List2BusinessJob, CODIReportJob</job-type>
      <!--任务完成后是否依然保存到数据库,默认为false-->
      <durable>true</durable>
      <!--应用或服务重启之后是否忽略过期任务,默认为false-->
      <recover>false</recover>
      <!--传递给IJobExecutionContext 上下文数据-->
      <job-data-map>
        <entry>
          <key>taskName</key>
          <value>List2Business</value>
        </entry>
        <entry>
          <key>taskNameCN</key>
          <value>定时发送 医院属性</value>
        </entry>
      </job-data-map>
    </job>
    <trigger>
      <!--复杂触发器,使用 cron-expression 设置触发器的行为 cron生成器:https://cron.qqe2.com/ -->
      <cron>
        <!--触发器名称,同一个 group 中作业名称不能相同-->
        <name>Tr_List2BusinessJob</name>
        <!--触发器分组名称,表示该触发器所属分组-->
        <group>GP_List2BusinessJob</group>
        <!--作业名,触发哪个作业,必须与 job 节点中的 group 相同-->
        <job-name>List2BusinessJob</job-name>
        <!--要调度的作业分组名称,必须与 job 节点中的 group 相同-->
        <job-group>jGP_List2BusinessJob</job-group>
        <!--开始作业的 utc 时间,北京时间需要+08:00,例如:<start-time>2017-12-01T08:00:00+08:00</start-time>,表示北京时间2017年12月1日上午8:00开始执行。
          注意:服务启动或重启时都会检测此属性。若没有设置此属性,服务会根据 cron-expression 的规则执行作业调度;
          若 start-time 的时间小于当前时间,服务启动后会忽略 cron-expression 的设置,立即执行一次调度,之后再根据 cron-expression 执行作业调度;
          若大于当前时间,服务会等到当前时间等于 start-time 的时间才开始执行,并根据 cron-expression 执行作业调度。
          如果没有特殊要求,可以忽略该属性。-->
        <!--<start-time>2021-12-01T00:00:00+08:00</start-time>-->
        <!--错过了触发 必须在 cron-expression 节点前
          DoNothing:不触发立即执行。等待下次Cron触发频率到达时刻开始按照Cron频率依次执行。即如果错过了某次执行,直接忽略。
          FireOnceNow:以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行。-->
        <misfire-instruction>SmartPolicy</misfire-instruction>
        <!--每1分钟执行一次-->
        <cron-expression>0 */1 * * * ?</cron-expression>
      </cron>
    </trigger>
  </schedule>
</job-scheduling-data>

2.5 Job代码

    /// <summary>
    /// 定时发送
    /// PersistJobDataAfterExecution: 执行完Job后保存 JobDataMap 当中固定数据,以便任务在重复执行的时候具有相同的 JobDataMap
    /// DisallowConcurrentExecution:不能同时运行同一作业的多个实例
    /// </summary>
    [PersistJobDataAfterExecution, DisallowConcurrentExecution]
    public class List2BusinessJob : IJob
    {
        ILogger<List2BusinessJob> _logger;
        AutoSendSalesDailyReportJobTask _AutoSendJobTask;
        public List2BusinessJob(ILogger<List2BusinessJob> logger, AutoSendSalesDailyReportJobTask AutoSendJobTask)
        {
            _logger = logger;
            _AutoSendJobTask = AutoSendJobTask;
        }

        public async Task Execute(IJobExecutionContext context)
        {
            AutoSendSalesDailyReportJobTask.setLogger(_logger);
            context.JobDetail.JobDataMap.TryGetValue("taskName", out object _taskName);
            context.JobDetail.JobDataMap.TryGetValue("taskNameCN", out object _taskNameCN);
            ThreadContext.Properties["taskName"] = _taskName ?? "List2Business";
            LogicalThreadContext.Properties["taskName"] = _taskName ?? "List2Business";
            ThreadContext.Properties["taskNameCN"] = _taskNameCN ?? "定时发送Job";
            LogicalThreadContext.Properties["taskNameCN"] = _taskNameCN ?? "定时发送Job";

            try
            {
                _logger.LogInformation($"Start Execute:Job开始执行");
                //具体执行逻辑方法
                await _AutoSendJobTask.BeginTaskAsync("List");
            }
            catch (Exception ex)
            {
                _logger.LogError("Execute List2BusinessJob error:", ex.Message);
            }
            finally
            {
                _logger.LogInformation($"End Execute:Job执行结束");
            }
        }
    }

最后 通过 sc create reportjob binPath="exePath" 就可以创建服务了。

Microsoft.Extensions.Hosting 可以绑定 asp.net core 程序可以是framework 4.6.1 以后的任意应用程序,快速 创建 集 configuration、dependency injection、logging 的应用,自动管理应用 生命周期。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值