الكوارتز في ASP.NET Core

المقدمة


أعلم أن هناك الكثير من المقالات ونوعًا من الدروس حول هذا الموضوع ، حتى أنني لا أتحدث عن الوثائق الرسمية ، ولكن عند العمل على مشروعي الأخير ، واجهت مشكلة مثيرة للاهتمام للغاية ، والتي لم يتم ذكرها كثيرًا. سنتحدث اليوم عن مشكلة استخدام حقن التبعية والكوارتز في مشروع ASP.NET Core.

بدأ كل شيء بحقيقة أنني لم أعتقد أنه يمكن أن تنشأ أي مشاكل وأقول على الفور أنني حاولت استخدام أساليب مختلفة: أضفت جميع الفئات التي أدرجتها الكوارتز في الخدمات واستخدمتها من خلال DI - بواسطة (ولكن ليس تمامًا ، كما اتضح لاحقًا) ، حاولت إضافة HostedService - لكنها لم تنجح أيضًا (في النهاية سأرفق بعض الروابط الجيدة لمقالات مفيدة حول العمل مع الكوارتز) وما إلى ذلك. لقد اعتقدت بالفعل أن لدي مشكلة مع الزناد - ولا. في هذا المقال القصير ، سأحاول مساعدة أولئك الذين ربما واجهوا نفس المشكلة ، وآمل أن يساعدهم حلّي في عملهم المستقبلي. في نهاية المقدمة ، أود أن أضيف أنني سأكون ممتنًا جدًا إذا قدم الأشخاص الذين لديهم معرفة جيدة بالتكنولوجيا في التعليقات بعض النصائح التي ستساعد في تحسين ما اقترحته.

كوارتز


أنشئ مشروعًا (أو خذ مشروعًا نهائيًا - لا يهم) وأضف مجلدين وعدة فئات إليه:

الكوارتز -
DataJob.cs -
DataScheduler.cs
--JobFactory.cs
العمال -
البريد الإلكتروني
المرسل - البريد الإلكتروني

في واجهة 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. كل شيء جاهز تقريبًا ، يبقى تغيير فئة البرنامج:

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();
    }

وقم بإضافة ما يلي إلى Startup في طريقة ConfigureServices:

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

منجز. الآن عند بدء تشغيل التطبيق ، نقوم بإنشاء مهمة ستطلق كل دقيقة. يمكن تغيير القيمة في DataScheduler.Start (يمكن أيضًا تحديدها في ثوانٍ أو ساعات أو استخدام CRON). لكل مهمة جديدة مع هذا النهج ، تحتاج إلى إنشاء فئة جديدة من شأنها تنفيذ IJob وتسجيل مهمة DataScheduler جديدة. يمكنك أيضًا إنشاء فصل مجدول منفصل لمهمة جديدة.

سأكون سعيدًا جدًا إذا كان بإمكاني مساعدة شخص ما ، ولكن إليك بعض المقالات المفيدة حول الكوارتز واستخدامه:

إنشاء خدمة استضافتها Quartz.NET باستخدام ASP.NET Core
باستخدام خدمات محددة النطاق داخل خدمة استضافتها Quartz.NET مع ASP.NET Core

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


All Articles