• ASP.NET Core MVC应用程序中的后台工作任务


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

  • 相关阅读:
    git版本库管理介绍,撤销git pull操作
    【laravel5.4】自定义404、503等页面
    【laravel5.4】{{$name}}、{{name}}、@{{$name}} 和 @{{name}} 的区别
    python 了解一点属性的延迟计算
    python 了解一下__dict__
    excel怎么把一个sheet的 全部内容打印到一页纸上
    python 简单了解一下 描述器
    python 调用父类方法, 重写父类构造方法, 不显式调用,会报错
    Python 今天抽空学习了@Property
    python 语法糖是什么意思
  • 原文地址:https://www.cnblogs.com/ZaraNet/p/10253833.html
Copyright © 2020-2023  润新知