ASP.NET Core中的石英

介绍


我知道关于这个主题有很多文章和某种教程,我什至没有在谈论官方文档,但是在进行我的最新项目时,遇到了一个非常有趣的问题,没有太多提及。今天,我们将讨论在ASP.NET Core项目中使用依赖注入和Quartz的问题。

一切始于我不认为会出现任何问题的事实,我会立即说我尝试使用各种方法:我添加了Quartz包含在服务中的所有类,并通过DI使用它们-by(但不完全是, (后来发现),我尝试添加HostedService-也不起作用(最后,我将在有关使用Quartz的有用文章上附加一些很好的链接)等等。我已经以为触发器有问题-两者都没有。在这篇简短的文章中,我将尝试帮助那些可能遇到相同问题的人,并希望我的解决方案对他们将来的工作有所帮助。在引言的结尾,我想补充一点,如果我在评论中对本技术非常了解的人给出一些建议,这些建议可以帮助改善我的建议,我将非常感激。

石英


创建一个项目(或完成一个项目-没关系),并向其中添加两个文件夹和几个类:

Quartz
--DataJob.cs
--DataScheduler.cs
--JobFactory.cs
Workers
--EmailSender
--IEmailSender

在IEmailSender界面中,将作为示例,创建一种向信件发送信件的方法:

public interface IEmailSender
    {
        Task SendEmailAsync(string email, string subject, string message);
    }

现在,我们描述将实现此接口的类:

public class EmailSender : IEmailSender
    {
        
        public Task SendEmailAsync(string email, string subject, string message)
		{
			var from = "****@gmail.com";
			var pass = "****";
            SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
			client.DeliveryMethod = SmtpDeliveryMethod.Network;
			client.UseDefaultCredentials = false;
			client.Credentials = new System.Net.NetworkCredential(from, pass);
			client.EnableSsl = true;
			var mail = new MailMessage(from, email);
			mail.Subject = subject;
			mail.Body = message;
			mail.IsBodyHtml = true;
			return client.SendMailAsync(mail);
		}
    }

现在,我们描述类DataJob.cs,DataScheduler.cs,JobFactory.cs。DataJob类将实现IJob接口。

 public class DataJob : IJob
    {
        private readonly IServiceScopeFactory serviceScopeFactory;

        public DataJob(IServiceScopeFactory serviceScopeFactory)
        {
            this.serviceScopeFactory = serviceScopeFactory;
        }

        public async Task Execute(IJobExecutionContext context)
        {
            using (var scope = serviceScopeFactory.CreateScope())
            {
                var emailsender = scope.ServiceProvider.GetService<IEmailSender>();
                
                 await emailsender.SendEmailAsync("example@gmail.com","example","hello")
            }
        }
    }

正如我们看到的IServiceScopeFactory类型的字段一样,我们将直接从Startup获取服务。正是这种方法帮助我解决了问题,继续描述了DataScheduler类,我们将在其中添加作业并在石英本身的Sheduler中进行触发:

public static class DataScheduler
    {
        
        public static async void Start(IServiceProvider serviceProvider)
        {
            IScheduler scheduler = await StdSchedulerFactory.GetDefaultScheduler();
            scheduler.JobFactory = serviceProvider.GetService<JobFactory>();
            await scheduler.Start();

            IJobDetail jobDetail = JobBuilder.Create<DataJob>().Build();
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("MailingTrigger", "default")
                .StartNow()
                .WithSimpleSchedule(x => x
                .WithIntervalInMinutes(1)
                .RepeatForever())
                .Build();

            await scheduler.ScheduleJob(jobDetail, trigger);
        }

现在是JobFactory类,它实现了IJobFactory接口:

 public class JobFactory : IJobFactory
    {
        protected readonly IServiceScopeFactory serviceScopeFactory;

        
        public JobFactory(IServiceScopeFactory serviceScopeFactory)
        {
            this.serviceScopeFactory = serviceScopeFactory;
        }

        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            using (var scope = serviceScopeFactory.CreateScope())
            {
                var job = scope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob;
                return job;
            }
            
        }

        public void ReturnJob(IJob job)
        {
           //Do something if need
        }
    }

如您所见,实际上,我直接从serviceScopeFactory获取所有依赖项。一切准备就绪,仍然需要更改Program类:

public class Program
    {
        public static void Main(string[] args)
        {
            var host = BuildWebHost(args);
            using (var scope = host.Services.CreateScope())
            {
                var serviceProvider = scope.ServiceProvider;
                try
                {
                    DataScheduler.Start(serviceProvider);
                }
                catch (Exception)
                {
                    throw;
                }
            }
            host.Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
           WebHost.CreateDefaultBuilder(args)
               .UseStartup<Startup>()
               .Build();
    }

并将以下内容添加到“启动”中的ConfigureServices方法:

   services.AddTransient<JobFactory>();
   services.AddScoped<DataJob>();
   services.AddScoped<IEmailSender,EmailSender>();

做完了 现在,当您启动应用程序时,我们创建一个将在每分钟触发的任务。可以在DataScheduler.Start中更改该值(也可以以秒,小时为单位或使用CRON进行指定)。对于使用这种方法的每个新任务,您需要创建一个新类,该类将实现IJob并注册一个新的DataScheduler任务。您也可以为新任务创建单独的Scheduler类。

如果可以帮助某人,我将非常高兴,但是这里有几篇有关Quartz及其用法的有用文章:

使用ASP.NET Core创建Quartz.NET托管服务在ASP.NET Core中
使用Quartz.NET托管服务中的作用域服务

Source: https://habr.com/ru/post/undefined/


All Articles