diff --git a/.editorconfig b/.editorconfig
index 22ecf73..5c801f2 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -3,6 +3,7 @@ root = true
[*]
charset = utf-8
+insert_final_newline = true
# C# files
[*.cs]
@@ -15,8 +16,9 @@ indent_style = space
tab_width = 4
# New line preferences
-end_of_line = lf
-insert_final_newline = false
+insert_final_newline = true
+trim_trailing_whitespace = true
+
#### .NET Coding Conventions ####
@@ -37,7 +39,7 @@ dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
# Modifier preferences
-dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
# Expression-level preferences
csharp_style_deconstructed_variable_declaration = true:suggestion
@@ -65,9 +67,9 @@ dotnet_code_quality_unused_parameters = all:suggestion
#### C# Coding Conventions ####
# var preferences
-csharp_style_var_elsewhere = false:silent
-csharp_style_var_for_built_in_types = false:silent
-csharp_style_var_when_type_is_apparent = false:silent
+csharp_style_var_elsewhere = true:silent
+csharp_style_var_for_built_in_types = true:silent
+csharp_style_var_when_type_is_apparent = true:silent
# Expression-bodied members
csharp_style_expression_bodied_accessors = true:silent
@@ -87,7 +89,7 @@ csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
-csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
+csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async
# Code-block preferences
csharp_prefer_braces = true:silent
@@ -100,6 +102,12 @@ csharp_style_prefer_range_operator = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+# C# 10
+csharp_style_namespace_declarations = file_scoped:error
+csharp_style_prefer_primary_constructors = true
+dotnet_diagnostic.IDE0290.severity = error
+
+
#### C# Formatting Rules ####
# New line preferences
@@ -146,3 +154,9 @@ csharp_space_between_square_brackets = false
# Wrapping preferences
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
+
+
+[*.csproj]
+indent_size = 2
+indent_style = space
+tab_width = 2
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 0b08b04..1c1992c 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -15,10 +15,10 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-dotnet@v3
+ - uses: actions/checkout@v4
+ - uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.0.x
+ dotnet-version: 9.0.x
- run: dotnet --info
- name: Restore dependencies
run: dotnet restore
diff --git a/.github/workflows/PreRelease.yml b/.github/workflows/PreRelease.yml
index 3177b06..ae51f91 100644
--- a/.github/workflows/PreRelease.yml
+++ b/.github/workflows/PreRelease.yml
@@ -8,12 +8,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- - uses: actions/setup-dotnet@v3
+ - uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.0.x
+ dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml
index d12996e..00b91bd 100644
--- a/.github/workflows/Release.yml
+++ b/.github/workflows/Release.yml
@@ -11,9 +11,9 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- - uses: actions/setup-dotnet@v3
+ - uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.0.x
+ dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
diff --git a/src/CronBackgroundServices/CronBackgroundService.cs b/src/CronBackgroundServices/CronBackgroundService.cs
index 8b309c0..f871340 100644
--- a/src/CronBackgroundServices/CronBackgroundService.cs
+++ b/src/CronBackgroundServices/CronBackgroundService.cs
@@ -3,25 +3,16 @@
namespace CronBackgroundServices;
-internal class CronBackgroundService : BackgroundService
+internal class CronBackgroundService(IRecurringAction Action, ILogger logger) : BackgroundService
{
- protected readonly IRecurringAction Action;
- private readonly ILogger _logger;
- private readonly Timing _timing;
+ private readonly Timing _timing = new(Action.GetTimeZoneId());
- public CronBackgroundService(IRecurringAction action, ILogger logger)
- {
- _timing = new Timing(action.GetTimeZoneId());
- Action = action;
- _logger = logger;
- Cron = action.Cron;
- _logger.LogTrace($"Using {Cron} and timezone '{_timing.TimeZoneInfo.Id}. The time in this timezone: {_timing.RelativeNow()}'");
- }
-
- private string Cron { get; }
+ private string Cron { get; } = Action.Cron;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
+ logger.LogTrace(
+ $"Using {Cron} and timezone '{_timing.TimeZoneInfo.Id}. The time in this timezone: {_timing.RelativeNow()}'");
DateTimeOffset? next = null;
do
@@ -33,7 +24,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
next = _timing.GetNextOccurenceInRelativeTime(Cron);
var uText = _timing.Get10NextOccurrences(Cron);
var logText = $"Ten next occurrences :\n{uText.Aggregate((x, y) => x + "\n" + y)}";
- _logger.LogTrace(logText);
+ logger.LogTrace(logText);
}
if (now > next)
@@ -44,11 +35,13 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
}
catch (Exception e)
{
- _logger.LogError(e, e.Message);
+ logger.LogError(e, e.Message);
}
next = _timing.GetNextOccurenceInRelativeTime(Cron);
- _logger.LogTrace($"Next at {next.Value.DateTime.ToLongDateString()} {next.Value.DateTime.ToLongTimeString()}");
+ logger.LogTrace(next is not null
+ ? $"Next at {next.Value.DateTime.ToLongDateString()} {next.Value.DateTime.ToLongTimeString()}"
+ : "No more occurences.");
}
else
{
@@ -57,7 +50,6 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
// cron occurence (lowest possible: every second)
await Task.Delay(100);
}
-
} while (!stoppingToken.IsCancellationRequested);
}
}
diff --git a/src/CronBackgroundServices/CronBackgroundServices.csproj b/src/CronBackgroundServices/CronBackgroundServices.csproj
index 465cabf..fd9fe6d 100644
--- a/src/CronBackgroundServices/CronBackgroundServices.csproj
+++ b/src/CronBackgroundServices/CronBackgroundServices.csproj
@@ -1,38 +1,33 @@
-
- net8.0;net7.0
- CronBackgroundServices
- CronBackgroundServices
- John Korsnes
-
- A .NET Core Background Service using Cron expressions as triggers
-
- dotnetcore
- https://github.com/slackbot-net/slackbot.net
- https://github.com/slackbot-net/slackbot.net/blob/master/LICENSE
- https://github.com/slackbot-net/slackbot.net
- images/cron.png
- cron.png
- git
- enable
- latest
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ net8.0;net9.0
+ CronBackgroundServices
+ CronBackgroundServices
+ John Korsnes
+
+ A .NET Core Background Service using Cron expressions as triggers
+
+ dotnetcore
+ https://github.com/slackbot-net/slackbot.net
+ https://github.com/slackbot-net/slackbot.net/blob/master/LICENSE
+ https://github.com/slackbot-net/slackbot.net
+ images/cron.png
+ cron.png
+ git
+ enable
+ enable
+ latest
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/CronBackgroundServices/Hosting/ServiceCollectionExtensions.cs b/src/CronBackgroundServices/Hosting/ServiceCollectionExtensions.cs
index 824ea97..5fcd1c9 100644
--- a/src/CronBackgroundServices/Hosting/ServiceCollectionExtensions.cs
+++ b/src/CronBackgroundServices/Hosting/ServiceCollectionExtensions.cs
@@ -4,10 +4,10 @@
namespace CronBackgroundServices;
-public static class SlackbotWorkerBuilderExtensions
+public static class ServiceCollectionExtensions
{
///
- /// For distributed apps
+ /// For distributed apps
///
public static IServiceCollection AddRecurrer(this IServiceCollection services) where T : class, IRecurringAction
{
@@ -16,7 +16,7 @@ public static IServiceCollection AddRecurrer(this IServiceCollection services
{
var allRecurrers = s.GetServices();
var single = allRecurrers.First(r => r is T);
- var loggerFactory = s.GetService();
+ var loggerFactory = s.GetRequiredService();
var logger = loggerFactory.CreateLogger();
return new CronBackgroundService(single, logger);
});
diff --git a/src/CronBackgroundServices/IRecurringAction.cs b/src/CronBackgroundServices/IRecurringAction.cs
index a5353d0..f473670 100644
--- a/src/CronBackgroundServices/IRecurringAction.cs
+++ b/src/CronBackgroundServices/IRecurringAction.cs
@@ -5,29 +5,28 @@ namespace CronBackgroundServices;
public interface IRecurringAction
{
///
- /// The job to be executed at intervals defined by the Cron expression
+ /// The cron expression (including seconds) as defined by the Cronos library:
+ /// See https://github.com/HangfireIO/Cronos#cron-format
+ /// Ex: Every second: */1 * * * * *
+ /// Ex: Every minute: 0 */1 * * * *
+ /// Ex: Every midnight: 0 0 */1 * * *
+ /// Ex: First of every month 0 0 0 1 * *
///
- ///
- Task Process(CancellationToken stoppingToken);
+ /// A valid Cron Expression
+ string Cron { get; }
///
- /// The cron expression (including seconds) as defined by the Cronos library:
- /// See https://github.com/HangfireIO/Cronos#cron-format
- /// Ex: Every second: */1 * * * * *
- /// Ex: Every minute: 0 */1 * * * *
- /// Ex: Every midnight: 0 0 */1 * * *
- /// Ex: First of every month 0 0 0 1 * *
+ /// The job to be executed at intervals defined by the Cron expression
///
- /// A valid Cron Expression
- string Cron { get; }
+ ///
+ Task Process(CancellationToken stoppingToken);
///
- /// Optional: The TimeZone in which the Cron expression should be based on.
- /// Defaults to UTC (Europe/London or GMT Standard Time)
- ///
- /// NB! When overriding this and targeting versions below .NET 6, use platform specific identifiers
- /// If your runtime is .NET 6 or above, it's not required. It will handles the conversion:
- /// See https://github.com/dotnet/runtime/pull/49412
+ /// Optional: The TimeZone in which the Cron expression should be based on.
+ /// Defaults to UTC (Europe/London or GMT Standard Time)
+ /// NB! When overriding this and targeting versions below .NET 6, use platform specific identifiers
+ /// If your runtime is .NET 6 or above, it's not required. It will handles the conversion:
+ /// See https://github.com/dotnet/runtime/pull/49412
///
/// timezoneId
string GetTimeZoneId()
diff --git a/src/CronBackgroundServices/Timing.cs b/src/CronBackgroundServices/Timing.cs
index 8082ae0..7c90133 100644
--- a/src/CronBackgroundServices/Timing.cs
+++ b/src/CronBackgroundServices/Timing.cs
@@ -2,14 +2,9 @@
namespace CronBackgroundServices;
-internal class Timing
+internal class Timing(string timeZoneId)
{
- public readonly TimeZoneInfo TimeZoneInfo;
-
- public Timing(string timeZoneId)
- {
- TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
- }
+ public readonly TimeZoneInfo TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
public DateTimeOffset RelativeNow(DateTimeOffset? nowutc = null)
{
@@ -27,11 +22,13 @@ public IEnumerable Get10NextOccurrences(string cron)
var expression = CronExpression.Parse(cron, CronFormat.IncludeSeconds);
var fromUtc = DateTime.UtcNow;
var upcoming = new List();
- upcoming.AddRange(Get10Occurrences(upcoming, expression, fromUtc, fromUtc.AddMonths(1)));
+ upcoming.AddRange(GetTenNextsOccurrences(upcoming, expression, fromUtc, fromUtc.AddMonths(1)));
return upcoming.Select(u => $"{u.ToLongDateString()} {u.ToLongTimeString()}");
}
- private IEnumerable Get10Occurrences(List upcoming, CronExpression expression, DateTime fromUtc, DateTime toUtc)
+ private IEnumerable GetTenNextsOccurrences(List upcoming, CronExpression expression,
+ DateTime fromUtc,
+ DateTime toUtc)
{
while (true)
{
@@ -43,9 +40,10 @@ private IEnumerable Get10Occurrences(List upcoming, CronExpr
{
continue;
}
+
break;
}
- return upcoming.Take(10);
+ return upcoming.Take(10);
}
}