Skip to content

Commit

Permalink
.NET 9 (#11)
Browse files Browse the repository at this point in the history
deprecate .NET 7
add .NET 9

+semver:major
  • Loading branch information
johnkors authored Feb 16, 2025
1 parent 6e5f44a commit a6b8d78
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 97 deletions.
28 changes: 21 additions & 7 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ root = true

[*]
charset = utf-8
insert_final_newline = true

# C# files
[*.cs]
Expand All @@ -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 ####

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
6 changes: 3 additions & 3 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/PreRelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/Release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 10 additions & 18 deletions src/CronBackgroundServices/CronBackgroundService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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
{
Expand All @@ -57,7 +50,6 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
// cron occurence (lowest possible: every second)
await Task.Delay(100);
}

} while (!stoppingToken.IsCancellationRequested);
}
}
63 changes: 29 additions & 34 deletions src/CronBackgroundServices/CronBackgroundServices.csproj
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net7.0</TargetFrameworks>
<RootNamespace>CronBackgroundServices</RootNamespace>
<PackageId>CronBackgroundServices</PackageId>
<Authors>John Korsnes</Authors>
<Description>
A .NET Core Background Service using Cron expressions as triggers
</Description>
<PackageTags>dotnetcore</PackageTags>
<PackageProjectUrl>https://github.com/slackbot-net/slackbot.net</PackageProjectUrl>
<License>https://github.com/slackbot-net/slackbot.net/blob/master/LICENSE</License>
<RepositoryUrl>https://github.com/slackbot-net/slackbot.net</RepositoryUrl>
<PackageIconUrl>images/cron.png</PackageIconUrl>
<PackageIcon>cron.png</PackageIcon>
<RepositoryType>git</RepositoryType>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Cronos" Version="0.7.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
</ItemGroup>

<ItemGroup>
<None Include="images/cron.png" Pack="true" PackagePath="" />
</ItemGroup>
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<RootNamespace>CronBackgroundServices</RootNamespace>
<PackageId>CronBackgroundServices</PackageId>
<Authors>John Korsnes</Authors>
<Description>
A .NET Core Background Service using Cron expressions as triggers
</Description>
<PackageTags>dotnetcore</PackageTags>
<PackageProjectUrl>https://github.com/slackbot-net/slackbot.net</PackageProjectUrl>
<License>https://github.com/slackbot-net/slackbot.net/blob/master/LICENSE</License>
<RepositoryUrl>https://github.com/slackbot-net/slackbot.net</RepositoryUrl>
<PackageIconUrl>images/cron.png</PackageIconUrl>
<PackageIcon>cron.png</PackageIcon>
<RepositoryType>git</RepositoryType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Cronos" Version="0.7.1"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0"/>
</ItemGroup>
<ItemGroup>
<None Include="images/cron.png" Pack="true" PackagePath=""/>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

namespace CronBackgroundServices;

public static class SlackbotWorkerBuilderExtensions
public static class ServiceCollectionExtensions
{
/// <summary>
/// For distributed apps
/// For distributed apps
/// </summary>
public static IServiceCollection AddRecurrer<T>(this IServiceCollection services) where T : class, IRecurringAction
{
Expand All @@ -16,7 +16,7 @@ public static IServiceCollection AddRecurrer<T>(this IServiceCollection services
{
var allRecurrers = s.GetServices<IRecurringAction>();
var single = allRecurrers.First(r => r is T);
var loggerFactory = s.GetService<ILoggerFactory>();
var loggerFactory = s.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<T>();
return new CronBackgroundService(single, logger);
});
Expand Down
33 changes: 16 additions & 17 deletions src/CronBackgroundServices/IRecurringAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,28 @@ namespace CronBackgroundServices;
public interface IRecurringAction
{
/// <summary>
/// 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 * *
/// </summary>
/// <returns></returns>
Task Process(CancellationToken stoppingToken);
/// <returns>A valid Cron Expression</returns>
string Cron { get; }

/// <summary>
/// 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
/// </summary>
/// <returns>A valid Cron Expression</returns>
string Cron { get; }
/// <returns></returns>
Task Process(CancellationToken stoppingToken);

/// <summary>
/// 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
/// </summary>
/// <returns>timezoneId</returns>
string GetTimeZoneId()
Expand Down
18 changes: 8 additions & 10 deletions src/CronBackgroundServices/Timing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -27,11 +22,13 @@ public IEnumerable<string> Get10NextOccurrences(string cron)
var expression = CronExpression.Parse(cron, CronFormat.IncludeSeconds);
var fromUtc = DateTime.UtcNow;
var upcoming = new List<DateTime>();
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<DateTime> Get10Occurrences(List<DateTime> upcoming, CronExpression expression, DateTime fromUtc, DateTime toUtc)
private IEnumerable<DateTime> GetTenNextsOccurrences(List<DateTime> upcoming, CronExpression expression,
DateTime fromUtc,
DateTime toUtc)
{
while (true)
{
Expand All @@ -43,9 +40,10 @@ private IEnumerable<DateTime> Get10Occurrences(List<DateTime> upcoming, CronExpr
{
continue;
}

break;
}
return upcoming.Take(10);

return upcoming.Take(10);
}
}

0 comments on commit a6b8d78

Please sign in to comment.