在应用程序的内存中缓存常见数据(如查找)可以显着提高您的MVC Web应用程序性能和响应时间。当然,这些数据必须定期刷新。


  当然你可以使用任何方法来更新数据,例如Redis中就提供了设定缓存对象的生命时间,那么对于这种单对象的更新的做法我觉得是不符合我的编程习惯的,我们可以使用QuartZ.NET
框架来进行任务调度,我们在任务计划中进行统一的缓存更新,也就达到了我们的目的。

  Quartz受到良好支持,跨平台库可用于在应用程序内部调度任务。由于ASP.NET Core架构和开箱即用的中间件支持,在.NET Core MVC
Web应用程序中使用它有点不同。在本文中,我将尝试使用ASP.NET核心应用程序中的Quartz来解释后台工作者计划任务的简单计划。

  我使用简单的ASP.NET Core WebApi项目模板作为示例项目的基础。
由于我们不会关注端点的实际响应,而是关注Startup.cs依赖注入部分和中间件,默认的WebApi项目模板就好了。

  作为第一步我们应该引用Quartz框架,我将使用Nuget管理器,我现在使用的工具是Visual Studio 2019 体验版。
Install-Package Quartz -Version 3.0.7
  如果你在Linux或Mac Os上进行开发,那么请安装.net core sdk 在使用.net 脚手架来进行引入。
dotnet add package Quartz --version 3.0.7

  由于ASP.NET
Core具有开箱即用的依赖注入支持,我们需要在启动时设置我们的解析器,但在我们这样做之前,我们需要编写我们将用于设置调度的一些Quartz接口的实现我们项目中的任务。

  我们首先需要编写我们的任务,即将按特定时间表执行的代码单元。为此,我们需要在我们的作业类中实现  Quartz.IJob接口。
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging;
using Quartz; using System; using System.Threading.Tasks; namespace
Schedule.WebApiCore.Sample.Schedule {public class ScheduledJob : IJob { private
readonly IConfiguration configuration; private readonly ILogger<ScheduledJob>
logger;public ScheduledJob(IConfiguration configuration, ILogger<ScheduledJob>
logger) {this.logger = logger; this.configuration = configuration; } public
async Task Execute(IJobExecutionContext context) { this.logger.LogWarning($"
Hello from scheduled task {DateTime.Now.ToLongTimeString()}"); await
Task.CompletedTask; } } }

由于它只是一个示例应用程序,因此每次作业执行时,我只会在输出中写入当前时间的消息。将从Startup.cs类方法注入Microsoft.Extensions.Configuration.IConfiguration和
Microsoft.Extensions.Logging.ILogger接口实现的实例

我们需要实现的下一个接口是Quartz.Spi.IjobFactory。
using Quartz; using Quartz.Spi; using System; namespace
Schedule.WebApiCore.Sample.Schedule {public class ScheduledJobFactory :
IJobFactory {private readonly IServiceProvider serviceProvider; public
ScheduledJobFactory(IServiceProvider serviceProvider) {this.serviceProvider =
serviceProvider; }public IJob NewJob(TriggerFiredBundle bundle, IScheduler
scheduler) {return serviceProvider.GetService(typeof(IJob)) as IJob; } public
void ReturnJob(IJob job) { var disposable = job as IDisposable; if (disposable
!=null) { disposable.Dispose(); } } } }
   我们将IJobFactory接口实现的实例分配给我们的IScheduler实例,该实例将用于在每个调度触发器上实例化作业实例。
现在在我们的Startup.cs中设置依赖注入解析器。

配置
using System; using System.IO; using Microsoft.AspNetCore.Builder; using
Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Mvc; using
Microsoft.Extensions.Configuration;using
Microsoft.Extensions.DependencyInjection;using Quartz; using Quartz.Impl; using
Quartz.Spi;using Schedule.WebApiCore.Sample.Schedule; namespace
Schedule.WebApiCore.Sample {public class Startup { public IConfiguration
Configuration {get; } public IHostingEnvironment HostingEnvironment { get; }
public Startup(IConfiguration configuration, IHostingEnvironment
hostingEnvironment) {this.HostingEnvironment = hostingEnvironment; this
.Configuration = configuration; } public void
ConfigureServices(IServiceCollection services) { services.AddLogging();
services.AddSingleton<IConfiguration>(new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json")
.AddJsonFile($"
appsettings.{this.HostingEnvironment.EnvironmentName.ToLower()}.json")
.Build());#region Configure Quartz DI services.Add(new ServiceDescriptor(typeof
(IJob),typeof(ScheduledJob), ServiceLifetime.Transient)); services.AddSingleton
<IJobFactory, ScheduledJobFactory>(); services.AddSingleton
<IJobDetail>(provider => { return JobBuilder.Create<ScheduledJob>()
.WithIdentity("Sample.job", "group1") .Build(); }); services.AddSingleton
<ITrigger>(provider => { return TriggerBuilder.Create() .WithIdentity($"
Sample.trigger", "group1") .StartNow() .WithSimpleSchedule (s =>
s.WithInterval(TimeSpan.FromSeconds(5)) .RepeatForever() ) .Build(); });
services.AddSingleton<IScheduler>(provider => { var schedulerFactory = new
StdSchedulerFactory();var scheduler = schedulerFactory.GetScheduler().Result;
scheduler.JobFactory= provider.GetService<IJobFactory>(); scheduler.Start();
return scheduler; }); #endregion services.AddMvc(); } // This method gets
called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
IScheduler scheduler) {if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage(); }
scheduler.ScheduleJob(app.ApplicationServices.GetService<IJobDetail>(),
app.ApplicationServices.GetService<ITrigger>()); app.UseMvc(); } } }


修改Startup.cs


  启动项目没有什么问题~但当你将所有部件放在Startup.cs中的一个地方时,这样更容易解释整个DI设置,在那里你可以看到所有的依赖关系和接口是如何解决的,但是从长远来看,这个Startup.cs应该是凌乱的它最终将成为维持的噩梦。
出于这个原因,我将整个DI包装到扩展方法中。

  综上所述,我们的.Net Core为我们提供了解决方案,那么把Quartz的代码全部放到一个静态类中,它将使用Quartz的Microsoft
依赖注入语句和管道的Microsoft.AspNetCore.Builder.IApplicationBuilder扩展  
Microsoft.Extensions.DependencyInjection.IServiceCollection 。


  就我个人而言,我喜欢在项目中创建一个Extensions文件夹,然后在其中写入类,再去Startup.cs中进行配置!QuartzExtensions定义如下:
public static class QuartzExtensions { public static void AddQuartz(this
IServiceCollection services, Type jobType) { services.Add(new ServiceDescriptor(
typeof(IJob), jobType, ServiceLifetime.Transient)); services.AddSingleton
<IJobFactory, ScheduledJobFactory>(); services.AddSingleton
<IJobDetail>(provider => { return JobBuilder.Create<ScheduledJob>()
.WithIdentity("Sample.job", "group1") .Build(); }); services.AddSingleton
<ITrigger>(provider => { return TriggerBuilder.Create() .WithIdentity($"
Sample.trigger", "group1") .StartNow() .WithSimpleSchedule (s =>
s.WithInterval(TimeSpan.FromSeconds(5)) .RepeatForever() ) .Build(); });
services.AddSingleton<IScheduler>(provider => { var schedulerFactory = new
StdSchedulerFactory();var scheduler = schedulerFactory.GetScheduler().Result;
scheduler.JobFactory= provider.GetService<IJobFactory>(); scheduler.Start();
return scheduler; }); } public static void UseQuartz(this IApplicationBuilder
app) { app.ApplicationServices.GetService<IScheduler>()
.ScheduleJob(app.ApplicationServices.GetService<IJobDetail>(),
app.ApplicationServices.GetService<ITrigger>() ); } }
现在我们的Startup.cs更清洁,更容易维护和扩展!
public class Startup { public IConfiguration Configuration { get; } public
IHostingEnvironment HostingEnvironment {get; } public Startup(IConfiguration
configuration, IHostingEnvironment hostingEnvironment) {this.HostingEnvironment
= hostingEnvironment; this.Configuration = configuration; } // This method gets
called by the runtime. Use this method to add services to the container. public
void ConfigureServices(IServiceCollection services) { services.AddLogging();
services.AddSingleton<IConfiguration>(new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json")
.AddJsonFile($"
appsettings.{this.HostingEnvironment.EnvironmentName.ToLower()}.json")
.Build()); services.AddQuartz(typeof(ScheduledJob)); services.AddMvc(); } //
This method gets called by the runtime. Use this method to configure the HTTP
request pipeline. public void Configure(IApplicationBuilder app,
IHostingEnvironment env) {if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage(); } app.UseQuartz(); app.UseMvc(); } }
再次启动项目,ok 通过~



 祝.Net Core 越来越好!

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信