在应用程序的内存中缓存常见数据(如查找)可以显着提高您的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. Java 开发, volatile 你必须了解一下

    上一篇文章说了 CAS 原理,其中说到了 Atomic* 类,他们实现原子操作的机制就依靠了 volatile 的内存可见性特性.如果还不了解 CAS 和 Atomic*,建议看一下我们说的 CAS ...

  2. Ubuntu 16.04下安装64位谷歌Chrome浏览器

    1.进入 Ubuntu 16.04 桌面,按下 Ctrl + Alt + t 键盘组合键,启动终端. 也可以按下 Win 键(或叫 Super 键),在 Dash 的搜索框中输入 terminal 或 ...

  3. apigateway-kong(一)简介及部署

    时隔三年,本人重出江湖,哈哈哈 浏览之前写的博客,有些深度还不是太够.篇幅太短,并且很多专题没有坚持写下去,部分技(dai)术(ma)没有从业务中抽离出来,本人感觉好遗憾--为此,痛下决心,重拾博客, ...

  4. TCP/IP协议——ARP详解

    本文主要讲述了ARP的作用.ARP分组格式.ARP高速缓存.免费ARP和代理ARP. 1.学习ARP前要了解的内容 建立TCP连接与ARP的关系 应用接受用户提交的数据,触发TCP建立连接,TCP的第 ...

  5. bolt_storage.go

    package, * time.Second})     if err != nil {         return nil, err     }     err = db.Update(func( ...

  6. go语言 nsq源码解读三 nsqlookupd源码nsqlookupd.go

    从本节开始,将逐步阅读nsq各模块的代码. 读一份代码,我的思路一般是: 1.了解用法,知道了怎么使用,对理解代码有宏观上有很大帮助. 2.了解各大模块的功能特点,同时再想想,如果让自己来实现这些模块 ...

  7. 我TM菜爆

    我怎么什么都能爆零啊! 我太神了!

  8. BZOJ_1800_[Ahoi2009]fly 飞行棋_乱搞

    BZOJ_1800_[Ahoi2009]fly 飞行棋_乱搞 Description 给出圆周上的若干个点,已知点与点之间的弧长,其值均为正整数,并依圆周顺序排列. 请找出这些点中有没有可以围成矩形的 ...

  9. 【Unity游戏开发】AssetBundle杂记--AssetBundle的二三事

    一.简介 马三在公司大部分时间做的都是游戏业务逻辑和编辑器工具等相关工作,因此对Unity AssetBundle这块的知识点并不是很熟悉,自己也是有打算想了解并熟悉一下AssetBundle,掌握一 ...

  10. 谈谈surging引擎的tcp、http、ws协议和如何容器化部署

    1.前言 分布式已经成为了当前最热门的话题,分布式框架也百花齐放,群雄逐鹿.从中心化服务治理框架,到去中心化分布式服务框架,再到分布式微服务引擎,这都是通过技术不断积累改进而形成的结果.esb,网关, ...