Introduction

Hangfire is good, but it’s missing a simple CRON Expression converter. The main goal is to get an app setting value from the config file and convert it to a CRON Expression. And at the end, that expression can be used by Hangfire.

App Settings

We will need three kind of settings in our config file to express the different type of recurrences.

Daily: The job will be executed every day at x hours. (TimeSpan)

Period: The job will be executed every x hours and/or x minutes. (TimeSpan)

CronExpression: Allow us to use a custom CRON Expression (string)

The key format is defined as follow: JobName.RecurrenceType

<appSettings>
  <add key = "MyFirstJob.PeriodRecurrence" value="00:05:00" />
  <add key = "MySecondJob.DailyRecurrence" value="00:02:00" />
  <add key = "MyLastJob.CronExpression" value="2 2 * * *" />
</appSettings>
Code language: C# (cs)

Domain

I created a small class to manipulate easily the CRON Expression. We will enrich that code later when we will play with seconds.

public class CronInfo
{
    public string CronExpression { get; set; }

    public CronInfo(string cronExpression)
    {
        CronExpression = cronExpression;
    }
}
Code language: C# (cs)

The switch

It’s time to convert our app settings to an object CronInfo. In the first part we identify which kind of CRON Expression the setting is. When it’s done, we call one of our future converter ConverterFromXXXX

public static CronInfo ConvertFromConfig(string jobName)
{
    try
    {
        if (TimeSpan.TryParse(ConfigurationManager.AppSettings[$"{jobName}.PeriodRecurrence"], out var periodRecurrence))
            return ConvertFromPeriodRecurrence(periodRecurrence);

        if (TimeSpan.TryParse(ConfigurationManager.AppSettings[$"{jobName}.DailyRecurrence"], out var dailyRecurrence))
            return ConvertFromPeriodRecurrence(dailyRecurrence);

        string cronExpression = ConfigurationManager.AppSettings[$"{jobName}.CronExpression"];

        if (!string.IsNullOrEmpty(cronExpression)) return ConvertFromCronExpression(cronExpression);
    }
    catch (Exception)
    {
        Console.WriteLine($"The job with name {jobName} don't have recurence specified in the config.");
    }

    return null;
}
Code language: C# (cs)

The Converters

In the period recurrence converter, we have only 3 possibilities. You can specify the hours and/or the minutes. So we create the CRON Expression like this x */x * * *.

The second option is to use only the minute. In that case we should see something like this */x * * * *

As you can see we can’t allow the seconds. Hangfire don’t support recurrence less than 1 minute. This is why the last case is always */1 * * * * But if you are interested to know how to manage a task that is executed every x seconds, please have a look at this other post.

public static CronInfo ConvertFromPeriodRecurrence(TimeSpan periodRecurrence)
{
    if (periodRecurrence.Hours >= 1)
    {
        if (periodRecurrence.Seconds != 0) throw new ArgumentException("Seconds not allowed when hours are specified.");

        return new CronInfo($"{periodRecurrence.Minutes} */{periodRecurrence.Hours} * * *");
    }

    if (periodRecurrence.Minutes > 1)
    {
        if (periodRecurrence.Seconds != 0) throw new ArgumentException("Seconds not allowed when minutes are specified.");

        return new CronInfo($"*/{periodRecurrence.Minutes} * * * *");
    }

    return new CronInfo($"*/1 * * * *");
}
Code language: C# (cs)

Be careful, we can’t use the seconds in the daily recurrence. We only take the hours and minutes.

public static CronInfo ConvertFromDailyRecurrence(TimeSpan dailyRecurrence)
{
    if (dailyRecurrence.Seconds != 0) throw new ArgumentException("Seconds not allowed for daily recurrence.");

    return new CronInfo($"{dailyRecurrence.Minutes} {dailyRecurrence.Hours} * * *");
}
Code language: C# (cs)

We can only create a CRON Expression with a string value.

public static CronInfo ConvertFromCronExpression(string cronExpression)
{
    return new CronInfo(cronExpression);
}
Code language: C# (cs)

Happy coding! 🙂