by Vesselin Vassilev
Last Updated On Apr 2, 2018

It consists of five parts:
- minute
- hour
- day of month
- month
- day of week
Example:
50 11 * * * - means every day at 11:50AM
0 4 1,10 * * - means every 1st and 10th day of the month, at 4:00AM
20 4 * * SUN - means every Sunday at 4:20AM
A great tool to use for creating/testing cron expressions is https://crontab.guru
Now, let's have a look at the code.
First, we register our custom scheduled task in Global.asax.cs:
using SitefinityWebApp.Custom.ScheduledTasks;using System;using Telerik.Sitefinity.Services;namespace SitefinityWebApp{ public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { SystemManager.ApplicationStart += SystemManager_ApplicationStart; } private void SystemManager_ApplicationStart(object sender, EventArgs e) { CustomScheduledTaskBase.RegisterCustomScheduledTasks(); } }}public static void RegisterCustomScheduledTasks(){ using (SchedulingManager manager = SchedulingManager.GetManager()) { List<ScheduledTaskData> allTasks = manager.GetTaskData().ToList(); // get all defined custom Scheduled tasks in this assembly var scootTasks = typeof(CustomScheduledTaskBase).Assembly .GetTypes() .Where(t => t.IsSubclassOf(typeof(CustomScheduledTaskBase)) && !t.IsAbstract) .Select(t => (CustomScheduledTaskBase)Activator.CreateInstance(t)); foreach (var task in scootTasks) { var taskData = allTasks.Where(t => t.TaskName == task.TaskName).ToList(); if (taskData.Count == 0) { task.ScheduleCrontabTask(); } else { foreach (var td in taskData) { // delete failed or stopped tasks and those that have been running for // more than 3 hours if ( td.Status == TaskStatus.Failed || td.Status == TaskStatus.Stopped || (td.IsRunning && td.LastModified.AddHours(3) < DateTime.UtcNow) ) { manager.DeleteTaskData(td); manager.SaveChanges(); } } } } }}public void ScheduleCrontabTask(){ using (var manager = SchedulingManager.GetManager()) { var task = (CustomScheduledTaskBase)Activator.CreateInstance(this.GetType()); task.Id = Guid.NewGuid(); task.ScheduleSpecType = "crontab"; task.Title = task.TaskName; task.ScheduleSpec = CrontabExpression; task.ExecuteTime = CrontabHelper.GetExecuteTime(CrontabExpression, scheduleSpecType); manager.AddTask(task); manager.SaveChanges(); }}using System;using System.Threading;namespace SitefinityWebApp.Custom.ScheduledTasks{ public class DemoScheduledTask : CustomScheduledTaskBase { public override string CrontabExpression { get { // you can read the value from a custom config section // execute the task every day at 11:50AM return "50 11 * * *"; } } protected override void ExecuteTheTask() { for (int i = 1; i <= 100; i++) { // this is useful if you are going to provide a UI that shows the current task progress this.UpdateProgress(i, "Doing stuff {0}".Arrange(i)); // do your stuff... Thread.Sleep(2000); } } }}<div class="row"> <label> You can manually start the task by clicking the button below </label> <div> <button class="sfLinkBtn sfSave" onclick="return start();">Manual Start Task</button> </div></div><div class="row" style="margin-top:50px;"> <div id="progressbar"></div> <div id="status" style="margin-top:30px;"></div></div><script> var $progress = null; var $status = $("#status"); var _intervalHandle = null; $(function () { // .container is the wrapper class of the parent Layout widget var $editDiv = $(".container"); if ($editDiv.parent().hasClass("sfHeader")) { // edit div is in the wrong place for some reason in SF 10.1 // we need to move it out of sfHeader, to become a sibling instead of child $editDiv.insertAfter(".sfHeader"); } // init kendo $progress = $("#progressbar").kendoProgressBar({ type: "percent" }).data("kendoProgressBar"); // in case user refreshes the page beginPolling(); }) function start() { $.ajax({ url: window.location.pathname + "/startScheduledTask?taskName=SitefinityWebApp.Custom.ScheduledTasks.DemoScheduledTask", type: "GET" }) .done(function (data) { if (data == "Success") { alert("The task has started successfully, you can check its status below"); beginPolling(); } }) .fail(function (jqXHR, textStatus) { console.log(jqXHR); alert(jqXHR.responseText); }); return false; } function beginPolling() { refreshProgressBar(); _intervalHandle = window.setInterval(function () { refreshProgressBar(); }, 1500); } function _removeHandlers() { if (_intervalHandle) { window.clearInterval(_intervalHandle); _intervalHandle = null; } } function refreshProgressBar() { // get task progress from Sitefinity Scheduling Service $.ajax({ url: "/Sitefinity/Services/SchedulingService.svc/taskName/SitefinityWebApp.Custom.ScheduledTasks.DemoScheduledTask/progress?providerName=", type: "GET" }) .done(function (data) { $progress.value(data.ProgressStatus); if (data.StatusMessage) $status.text(data.StatusMessage); else $status.text(""); if (data.ProgressStatus == 100 || data.Status != 1) { _removeHandlers(); } }) }</script>
https://gist.github.com/VesselinVassilev/89b04f4ce7cef2610590643bafe089ca