在应用程序的内存中缓存常见数据(如查找)可以显着提高您的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())
.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())
.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 越来越好!

ASP.NET Core MVC应用程序中的后台工作任务的更多相关文章

  1. 跨平台应用集成(在ASP.NET Core MVC 应用程序中集成 Microsoft Graph)

    作者:陈希章 发表于 2017年6月25日 谈一谈.NET 的跨平台 终于要写到这一篇了.跨平台的支持可以说是 Office 365 平台在设计伊始就考虑的目标.我在前面的文章已经提到过了,Micro ...

  2. 使用ASP.NET Core MVC应用程序中的ResponseCache属性处理缓存(转载)

    HTTP响应的缓存意味着当发出HTTP请求时,服务器生成的响应由浏览器或服务器存储在某个地方,以便在对同一资源的连续HTTP请求中重复使用.实质上,我们正在存储生成的响应,并将该响应重用于后续请求一段 ...

  3. 创建ASP.NET Core MVC应用程序(6)-添加验证

    创建ASP.NET Core MVC应用程序(6)-添加验证 DRY原则 DRY("Don't Repeat Yourself")是MVC的设计原则之一.ASP.NET MVC鼓励 ...

  4. 创建ASP.NET Core MVC应用程序(5)-添加查询功能 & 新字段

    创建ASP.NET Core MVC应用程序(5)-添加查询功能 & 新字段 添加查询功能 本文将实现通过Name查询用户信息. 首先更新GetAll方法以启用查询: public async ...

  5. 创建ASP.NET Core MVC应用程序(4)-添加CRUD动作方法和视图

    创建ASP.NET Core MVC应用程序(4)-添加CRUD动作方法和视图 创建CRUD动作方法及视图 参照VS自带的基架(Scaffold)系统-MVC Controller with view ...

  6. 创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表

    创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表 创建数据模型类(POCO类) 在Models文件夹下添 ...

  7. 创建ASP.NET Core MVC应用程序(2)-利用MySQL Connector NET连接到MySQL

    创建ASP.NET Core MVC应用程序(2)-利用MySQL Connector NET连接到MySQL 用惯.NET的研发人员都习惯性地使用SQLServer作为数据库.然而.NET Core ...

  8. 创建ASP.NET Core MVC应用程序(1)-添加Controller和View

    创建ASP.NET Core MVC应用程序(1)-添加Controller和View 参考文档:Getting started with ASP.NET Core MVC and Visual St ...

  9. Entity Framework Core系列之实战(ASP.NET Core MVC应用程序)

    本示例演示在ASP.NET 应用程序中使用EF CORE创建数据库并对其做基本的增删改查操作.当然我们默认你的机器上已经安装了.NET CORE SDK以及合适的IDE.本例使用的是Visual St ...

随机推荐

  1. 最新的爬虫工具requests-html

    使用Python开发的同学一定听说过Requsts库,它是一个用于发送HTTP请求的测试.如比我们用Python做基于HTTP协议的接口测试,那么一定会首选Requsts,因为它即简单又强大.现在作者 ...

  2. Linux用户和组管理,添加修改用户,添加修改组,加入组,移除组

    1.安全介绍3A Authentication: 认证,用户名和对应口令 Authorization: 授权,不同用户权限不同 Accouting/Audition: 审计 2. 所属者和所属组 us ...

  3. sql server 内存初探

    一. 前言 对于sql server 这个产品来说,内存这块是最重要的一个资源, 当我们新建一个会话,相同的sql语句查询第二次查询时间往往会比第一次快,特别是在sql统计或大量查询数据输出时,会有这 ...

  4. 【BZOJ 3924】[Zjoi2015]幻想乡战略游戏

    题目: 题解: 对点分树理解加深了233,膜拜zzh干翻紫荆花. 感谢zzh的讲解. 首先优化基于传统DP,假设树不发生变化,我们就可以利用DP求出带权重心. 考虑修改,我们思路不变,还是从root开 ...

  5. bzoj5250 [2018多省省队联测]秘密袭击

    博主蒟蒻,目前还不会动态dp,所以下面说的是一个并不优秀的暴力,我会补的! 我们考虑按权值从大到小依次点亮每个点,相同权值可以同时点亮,每次点亮后,我们进行一次树形背包. 处理出$f[i][j]$表示 ...

  6. 【状压dp】Bzoj1231 [Usaco2008 Nov]mixup2 混乱的奶牛

    Description 混乱的奶牛 [Don Piele, 2007] Farmer John的N(4 <= N <= 16)头奶牛中的每一头都有一个唯一的编号S_i (1 <= S ...

  7. BZOJ_1455_罗马游戏_可并堆

    BZOJ_1455_罗马游戏_可并堆 Description 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢 ...

  8. laravel 中路由的快速设置(只需一个控制器名就ok) 不用具体到方法

    routes/web.php 设置路由 Route::group(['middleware' => ['\iqiyi\Http\Middleware\VerifyCsrfToken::class ...

  9. mysql中利用group by过滤删除重复行

    DELETEFROM peopleWHERE peopleId IN (SELECT peopleId FROM people GROUP BY peopleId HAVING count(peopl ...

  10. 本地和svn都删除文件导致版本不同的问题

    想要删除一个项目中的文件,同是要删除svn上的文件. 自己操作 1.直接右键删除了本地项目中的一个目录的模块 2.右键删除了库中svn中的这个目录 3.同步本地和svn上的代码 4.问题出现了,本地和 ...