From 3181bc223c460c5ed104a1831f9d0d4219807e04 Mon Sep 17 00:00:00 2001 From: John Korsnes Date: Sun, 16 Feb 2025 17:34:58 +0100 Subject: [PATCH] .NET 9 deprecate .NET 7 +semver:major --- .editorconfig | 28 ++++++--- .github/workflows/CI.yml | 6 +- .github/workflows/PreRelease.yml | 6 +- .github/workflows/Release.yml | 4 +- .../CronBackgroundService.cs | 28 +++------ .../CronBackgroundServices.csproj | 63 +++++++++---------- .../Hosting/ServiceCollectionExtensions.cs | 6 +- .../IRecurringAction.cs | 33 +++++----- src/CronBackgroundServices/Timing.cs | 18 +++--- 9 files changed, 95 insertions(+), 97 deletions(-) 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); } }