locked
How to schedule tasks with timer using worker service in C# RRS feed

  • Question

  • Hello developers

    I have a config.json file that has few interfaces to implement on different times each day at specific time, how can I implement these tasks with worker service. how to call these interfaces from my config.json file and loop through all the interfaces and decide which task to start and and how can I list all tasks that are running.

    I wont to use that to monitor files in different directories and do some processing such moving or copying files.

    Thanks in advance for your help.

    here is my config.json file:

    {
      "configurations": [
        {
          "Interface_id": 1,
          "Source": "C:\\Users\\Sehammohamed\\SubFolderA\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderB\\",
          "Description": "Monitoring files between folder 1",
          "Interval": 5000,
          "TimerFireEveryDayAt12PM": {
            "Schedule_at": "50 12 * * *"//every 12.50 PM daily
          },
          "Timeout": "0 */5 * * * *", //five minutes
          "regx": {
            "Pattern": "^.*\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        },
        {
          "Interface_id": 2,
          "Source": "C:\\Users\\SubFolderC\\",
          "Destination": "C:\\Users\\SubFolderD\\",
          "Description": "Monitoring files between folder 2",
          "Interval": 5000,
          "TimerFireEveryDayAt12PM": {
            "Schedule_at": "50 12 * * *" //every 12.50 PM daily
          },
          "Timeout": "0 */5 * * * *", //five minutes
          "regx": {
            "Pattern": "^.*\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        }
      ]
    }

    Thursday, October 15, 2020 9:06 AM

Answers

  • Hi Seham_1981,

    Thank you for posting here.

    Based on your description, you would like to schedule tasks according to the json file.

    First, we need to parse the json file to get information.

    Like the following code:

                string json = File.ReadAllText("D:\\1.json");
                JObject data = JObject.Parse(json);
                var result = data.SelectTokens("configurations[*]");
                foreach (JToken item in result)
                {
                    string source = item.Value<string>("Source");
                    string Destination = item.Value<string>("Destination");
                    int interval= item.Value<int>("Interval");
                    var jToken = item.SelectToken("TimerFireEveryDayAt12PM.Schedule_at");
                    Console.WriteLine(source);
                    Console.WriteLine(Destination);
                    Console.WriteLine(interval);
                    Console.WriteLine(jToken.ToString());
                    Console.WriteLine("*****");
                }
    

    Result:

    Second, you can refer to the following link to Schedule a task.

    C# Timer: Schedule a Task

    Hope my advice can help you.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by Seham_1981 Friday, October 16, 2020 7:54 AM
    Friday, October 16, 2020 6:02 AM

All replies

  • Hi Seham_1981,

    Thank you for posting here.

    Based on your description, you would like to schedule tasks according to the json file.

    First, we need to parse the json file to get information.

    Like the following code:

                string json = File.ReadAllText("D:\\1.json");
                JObject data = JObject.Parse(json);
                var result = data.SelectTokens("configurations[*]");
                foreach (JToken item in result)
                {
                    string source = item.Value<string>("Source");
                    string Destination = item.Value<string>("Destination");
                    int interval= item.Value<int>("Interval");
                    var jToken = item.SelectToken("TimerFireEveryDayAt12PM.Schedule_at");
                    Console.WriteLine(source);
                    Console.WriteLine(Destination);
                    Console.WriteLine(interval);
                    Console.WriteLine(jToken.ToString());
                    Console.WriteLine("*****");
                }
    

    Result:

    Second, you can refer to the following link to Schedule a task.

    C# Timer: Schedule a Task

    Hope my advice can help you.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by Seham_1981 Friday, October 16, 2020 7:54 AM
    Friday, October 16, 2020 6:02 AM
  • Great article, you saved my day, Thanks very much 
    Friday, October 16, 2020 7:53 AM
  • Hi Jack

    I am doing exactly like your code but I don't why I am getting null for the Schedule at filed. I have tried different ways of parsing it and declaring in two different ways in my config file but it still null. any ideas of why I keep getting it as null.

    Even with the regx value as well getting null.

    Thanks very much for your help and time.

    Seham.

    I tried the two ways of declaring the the Schedule_at in config.json as follows and non of them worked.

     "TimerFireEveryDayAt12PM": {

            "Schedule_at": "50 12 * * *" //every 12.50 PM daily
          }

    the other way I declared it like the timeout filed.

    "Schedule_at": "50 12 * * *" 

    *************************************************************************************
    Here is my Configurations.cs where I declare the fields for the json file.
    {
        public class Configurations
        {
           public List<Configs> configurations { get; set; }
        }
        public class Configs
        {
            public string Interface_id { get; set; }
            public string Source { get; set; } 
            public string Destination { get; set; }
            public string Description { get; set; }
            public string Schedule_at { get; set; } //this is first way of doing it, getting null value
            public string Timeout { get; set; }
            public Regex Regx { get; set; }
        }

        public class TimerScheduleClass
        {
            public string Schedule { get; set; } //this is the other way of doing it but still getting null
        }

        //public class RegxType
        //{
        //    public Regex regx { get; set; }
        //}
    }

    my worker service code that calls the json file

     string schedule_at = item.Value<string>("Schedule_at");
    // var jToken = item.SelectToken("TimerFireEveryDayAt12PM.Schedule_at");

    both cases gives me null.

    Thanks

    Friday, October 16, 2020 8:45 AM
  • Hi Seham_1981,

    Thanks for the feedback.

    In my code, there is no need to create a class to get information from the json file.

    Please try again the following code to check if it works for you.

                string json = File.ReadAllText("D:\\1.json");
                JObject data = JObject.Parse(json);
                var result = data.SelectTokens("configurations[*]");
                foreach (JToken item in result)
                {
                    string source = item.Value<string>("Source");
                    string Destination = item.Value<string>("Destination");
                    int interval= item.Value<int>("Interval");
                    var Schedule_at = item.SelectToken("TimerFireEveryDayAt12PM.Schedule_at");
                    var regex = item.SelectToken("regx.Pattern");
                    Console.WriteLine(source);
                    Console.WriteLine(Destination);
                    Console.WriteLine(interval);
                    Console.WriteLine(Schedule_at.ToString());
                    Console.WriteLine(regex.ToString());
                    Console.WriteLine("*****");
                }

    Result:

    Besides, I added the regex filed.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, October 16, 2020 9:05 AM
  • Hi Jack,

    Thanks for the quick reply, still getting null value.

    I wonder if it is related to the StartAsync method of the service or the version of the VisualStodio 2019 that I am running at.

    What do you think the reason. The really strange behavior is that I am getting the timeout value but only the Schedule_at as null

    Again thanks a million for help and time.

    Config.json

    {
      "configurations": [
        {
          "Interface_id": 1,
          "Source": "C:\\Users\\Sehammohamed\\SubFolderA\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderB\\",
          "Description": "Monitoring files between folder 1",
          "TimerFireEveryDayAt12PM": {
            "Schedule_at": "50 12 * * *" //every 12.50 PM daily
          }, //every 12.50 PM daily 
          "Timeout": "0 */5 * * * *", //every five mins
          "Regx": {
            "Pattern": "^.*\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        },
        {
          "Interface_id": 2,
          "Source": "C:\\Users\\Sehammohamed\\SubFolderC\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderD\\",
          "Description": "Monitoring files between folder 2",
          "Timeout": "0 */5 * * * *", //every five mins
          "TimerFireEveryDayAt12PM": {
            "Schedule_at": "50 12 * * *" //every 12.50 PM daily
          },
          "Regx": {
            "Pattern": "^.*\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        }
      ]
    }

    *************************WorkerService code**********************

    public  async Task StartAsync(CancellationToken cancellationToken)
            {
                Debugger.Launch();
                // eventLog1.WriteEntry("Service started...");
                _logger.LogInformation("Service started ...");

                string json = File.ReadAllText(@"C:\Users\SehamMohamed\source\repos\WorkerServiceApp\WorkerService\Config.json");
                JObject data = JObject.Parse(json);
                var result = data.SelectTokens("configurations[*]");
                foreach (JToken item in result)
                {
                    string source = item.Value<string>("Source");
                    string Destination = item.Value<string>("Destination");
                    string timeout = item.Value<string>("Timeout");
                    var Schedule_at = item.SelectToken("TimerFireEveryDayAt12PM.Schedule_at");
                    var regex = item.SelectToken("regx.Pattern");
                    Console.WriteLine(source);
                    Console.WriteLine(Destination);
                    Console.WriteLine(timeout);
                    Console.WriteLine(Schedule_at.ToString());
                    Console.WriteLine(regex.ToString());
                    Console.WriteLine("*****");
                }

               
            }

    Friday, October 16, 2020 9:33 AM
  • Hi Seham_1981,

    Sorry for the late reply.

    I used console app to to test it. Therefore, I suggest that you can try create a console app to test it.

    If you still get the null result, please check your json file if has the problem.

    If you get the correct result, I think it may be related to service.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, October 20, 2020 6:11 AM
  • Hi Jack,

    Thanks again for your reply and finally got working. I have another question if you do not mind helping me to sort it out. now I want to check which interface from the json file to run based on the cron expression value in the config. I have used the Task.Run() and in the call back function I passed the function That will rub=n the interface, but how will pass the schedule_at or run_at from Task.Run from my config.json to the runInterface function. here are my code:

    config.json //updated.*******************

    {
      "configurations": [
        {
          "Interface_id": "1",
          "Source": "C:\\Users\\Sehammohamed\\SubFolderA\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderB\\",
          "Description": "Moving files from folder 1",
          "TimerFireAtTheGivenTime": {
            "Runat": "0 */5 * * * *" //every 5 seconds
          },
          "Schedule_from": "2020-10-18T05:30:00",
          "Regx": {
            "Pattern": "^.*\\\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        },
        {
          "Interface_id": "2",
          "Source": "C:\\Users\\Sehammohamed\\SubFolderC\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderD\\",
          "Description": "Moving files from folder 2",
          "TimerFireAtTheGivenTime": {
            "Runat": "0 */5 * * * * " // runs every five seconds
          },
          "Schedule_from": "2020-10-18T05:30:00",
          "Regx": {
            "Pattern": "^.*\\\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        }
      ]
    }

    ***********************workerservice.cs*****************

                                                                                                                 

    using Cronos;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text.RegularExpressions;
    using System.Threading;
    using System.Threading.Tasks;

    namespace OASFileProcessing
    {
        public class Worker : BackgroundService
        {
            private readonly ILogger<Worker> _logger;
            public string rootPath;
            public string destPath;
            public CronExpression ranat;
            public string schedule_from;
            public Regex regx;
            DateTime startTime ;
            DateTime finishedTime;

            private Timer timer;

            public static List<InterfaceConfiguration> configs = new List<InterfaceConfiguration>();
            public static Dictionary<string, InterfaceMetaData> interfaceMetaData = new Dictionary<string, InterfaceMetaData>();

            private string jsonConfig = @"C:\Users\SehamMohamed\source\repos\WorkerServiceApp\WorkerService\Config.json";

            private long counter = 0;

            public Worker(ILogger<Worker> logger)
            {
                _logger = logger;
            }

            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                _logger.LogInformation("OAS FileMonitor started ...");
                try
                {
                    _logger.LogInformation("Reading configuration ...");

                    string json = File.ReadAllText(@"C:\TFS\OAS6\Features\OASIntegration\WorkerServiceApp\WorkerService\Config.json");
                    JObject data = JObject.Parse(json);
                    var result = data.SelectTokens("configurations[*]");
                    foreach (JToken item in result)
                    {
                        string source = item.Value<string>("Source");
                        string Destination = item.Value<string>("Destination");
                        var ranat = item.SelectToken("TimerFireAtTheGivenTime.Runat");
                        var schedule_from = item.Value<DateTime>("Schedule_from");
                        var regex = item.SelectToken("Regx.Pattern");
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogCritical("Error reading configuration file: " + jsonConfig);
                    _logger.LogCritical(ex.Message);
                    return;
                }
                while (!stoppingToken.IsCancellationRequested)
                {

                    counter++; // increment a counter so we can fire the interfaces every x seconds
                    foreach (InterfaceConfiguration interfaceConfig in configs)
                    {

                        DateTime now = DateTime.Now;
                        DateTime schedule_from = interfaceConfig.Schedule_from;

                        if (now < schedule_from)
                            return;

                        else if (now > schedule_from)
                        {
                            var runTime = interfaceConfig.Runat;

                            if (!interfaceMetaData.ContainsKey(interfaceConfig.Interface_id))
                            {
                                interfaceMetaData.Add(interfaceConfig.Interface_id, new InterfaceMetaData(interfaceConfig));
                            }
                            else
                            {
                                _logger.LogInformation(string.Format("Interface {1} last ran at: {0}", interfaceMetaData[interfaceConfig.Interface_id].LastRanAt, interfaceConfig.Interface_id));
                            }


                            _ = Task.Run(() => runInterface(interfaceMetaData[interfaceConfig.Interface_id], runTime), CancellationToken.None);

                        }
                    }
                    _logger.LogInformation(string.Format("Tick@{0}", DateTime.Now));

                    await Task.Delay(5000, stoppingToken);
                }
            }


            void runInterface(InterfaceMetaData InterfaceData, CronExpression runTime)
            {
                _logger.LogInformation("Interface " + InterfaceData.Configuration.Interface_id + " is running !");
                Console.WriteLine("Interface " + InterfaceData.Configuration.Interface_id + " is running !");

                try
                {
                    for (int i = 0; i < configs.Count; i++)
                    {
                        if (configs.Count > 0)
                        {
                            var interface_id = InterfaceData.Configuration.Interface_id;
                            rootPath = InterfaceData.Configuration.Source;
                            destPath = InterfaceData.Configuration.Destination;
                            regx = InterfaceData.Configuration.Regx;
                            ranat = runTime;
                            //runTime = configs[i].Runat;

                            bool directoryExists = Directory.Exists(destPath);
                            if (directoryExists)
                            {
                                // eventLog1.WriteEntry($"The [{rootPath}] exists.");
                                _logger.LogInformation($"The [{rootPath}] exists.");

                                var files = Directory.GetFiles(rootPath).OrderBy(f => new FileInfo(f).CreationTime).Where(item => regx.IsMatch(item));
                                // eventLog1.WriteEntry($"Moving files from Folder: {rootPath}");
                                _logger.LogInformation($"Moving files from Folder: {rootPath}");
                                foreach (var file in files)
                                {
                                    try
                                    {
                                        startTime = DateTime.Now;

                                        File.SetAttributes(destPath, FileAttributes.Normal);
                                        File.Move(file, $"{destPath}{Path.GetFileName(file)} ");
                                        //  eventLog1.WriteEntry($"File {Path.GetFileName(file)} moved to the the {destPath} successfullly");
                                        _logger.LogInformation($"File {Path.GetFileName(file)} moved to the the {destPath} successfullly");
                                        var finishedTime = DateTime.Now;
                                    }
                                    catch (IOException)
                                    {
                                        // eventLog1.WriteEntry($"Failed moving {Path.GetFileName(file)} to the {destPath}, File is being used by another process!", EventLogEntryType.Error);
                                        _logger.LogInformation($"Failed moving {Path.GetFileName(file)} to the {destPath}, File is being used by another process! ");
                                    }
                                    finally
                                    {
                                        TimeSpan timespan = finishedTime - startTime;
                                        InterfaceData.InterfaceRanFor = DateTime.FromOADate(timespan.TotalMilliseconds);
                                    }
                                }
                            }
                            else
                            {
                                Directory.CreateDirectory(destPath);
                            }
                        }
                    }
                }
                catch (Exception)
                {
                    // eventLog1.WriteEntry("Can not access folders over the network", EventLogEntryType.Error);
                    _logger.LogInformation("Can not access folders over the network");
                }
                finally
                {
                    InterfaceData.LastRanAt = DateTime.Now;

                    _logger.LogInformation("Interface " + InterfaceData.Configuration.Interface_id + " is finished !");
                    Console.WriteLine("Interface " + InterfaceData.Configuration.Interface_id + " is finished !");
                }
              }
            }
        }


    ************************Configurations.cs*****************

    using Cronos;
    using System;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;

    namespace OASFileProcessing
    {
        public class InterfaceConfigurations
        {
            public List<InterfaceConfiguration> Configurations { get; set; }
        }
        public class InterfaceConfiguration
        {
            public string Interface_id { get; set; }
            public string Source { get; set; }
            public string Destination { get; set; }
            public string Description { get; set; }
            public CronExpression Runat { get; set; }
            public DateTime Schedule_from { get; set; }
            public Regex Regx { get; set; }
        }
    }

    *************************InterfaceMetaData*****************************

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace OASFileProcessing
    {
        public class InterfaceMetaData
        {
            public DateTime LastRanAt { get; set; }
            public InterfaceConfiguration Configuration { get; set; }
            public DateTime InterfaceRanFor { get; internal set; }

            public InterfaceMetaData(InterfaceConfiguration config)
            {
                this.Configuration = config;
            }
        }*****************************

    Again thanks very much for your help and time, it's really appreciated.

    Seham.

    Tuesday, October 20, 2020 8:17 AM