diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 12f37c0..3980a5c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -8,7 +8,7 @@ Tingle Software Tingle Software $(PackageTags);periodic;tasks;cron;cronjob;scheduled - true + true diff --git a/src/Tingle.PeriodicTasks.AspNetCore/PeriodicTasksEndpointRouteBuilderExtensions.cs b/src/Tingle.PeriodicTasks.AspNetCore/PeriodicTasksEndpointRouteBuilderExtensions.cs index 57400fe..c1d9d26 100644 --- a/src/Tingle.PeriodicTasks.AspNetCore/PeriodicTasksEndpointRouteBuilderExtensions.cs +++ b/src/Tingle.PeriodicTasks.AspNetCore/PeriodicTasksEndpointRouteBuilderExtensions.cs @@ -13,14 +13,16 @@ namespace Microsoft.AspNetCore.Builder; /// public static class PeriodicTasksEndpointRouteBuilderExtensions { - internal const string MapEndpointTrimmerWarning = "This API may perform reflection on the supplied delegate and its parameters. These types may be trimmed if not directly referenced."; + private const string MapEndpointUnreferencedCodeWarning = "This API may perform reflection on the supplied delegate and its parameters. These types may be trimmed if not directly referenced."; + private const string MapEndpointDynamicCodeWarning = "This API may perform reflection on the supplied delegate and its parameters. These types may require generated code and aren't compatible with native AOT applications."; /// /// Maps incoming requests to the paths for periodic tasks. /// /// The to add the routes to. /// A for endpoints associated with periodic tasks. - [RequiresUnreferencedCode(MapEndpointTrimmerWarning)] + [RequiresUnreferencedCode(MapEndpointUnreferencedCodeWarning)] + [RequiresDynamicCode(MapEndpointDynamicCodeWarning)] public static IEndpointConventionBuilder MapPeriodicTasks(this IEndpointRouteBuilder endpoints) { ArgumentNullException.ThrowIfNull(endpoints); diff --git a/src/Tingle.PeriodicTasks.AspNetCore/PeriodicTasksEndpointsHandler.cs b/src/Tingle.PeriodicTasks.AspNetCore/PeriodicTasksEndpointsHandler.cs index c3611f7..abaf2a0 100644 --- a/src/Tingle.PeriodicTasks.AspNetCore/PeriodicTasksEndpointsHandler.cs +++ b/src/Tingle.PeriodicTasks.AspNetCore/PeriodicTasksEndpointsHandler.cs @@ -12,7 +12,7 @@ public List GetRegistrations() { var registrations = hostOptions.Registrations; var results = new List(); - foreach (var (name, type) in registrations) + foreach (var (name, (type, _)) in registrations) { var options = optionsMonitor.Get(name); results.Add(new() diff --git a/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTaskConfigureOptions.cs b/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTaskConfigureOptions.cs index 877a691..ea63b82 100644 --- a/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTaskConfigureOptions.cs +++ b/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTaskConfigureOptions.cs @@ -24,7 +24,7 @@ public void Configure(string? name, PeriodicTaskOptions options) ArgumentException.ThrowIfNullOrEmpty(name); // set schedule and timezone from Attribute - var type = tasksHostOptions.Registrations[name]; + var (type, _) = tasksHostOptions.Registrations[name]; var attrs = type.GetCustomAttributes(false); if (attrs.OfType().SingleOrDefault() is PeriodicTaskScheduleAttribute attrSchedule) { diff --git a/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTasksBuilder.cs b/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTasksBuilder.cs index 5ae5215..c7dda25 100644 --- a/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTasksBuilder.cs +++ b/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTasksBuilder.cs @@ -85,8 +85,6 @@ public PeriodicTasksBuilder Configure(Action configure { ArgumentNullException.ThrowIfNull(configure); - var tt = typeof(TTask); - Configure(opt => { if (opt.Registrations.TryGetValue(name, out var r)) @@ -94,7 +92,7 @@ public PeriodicTasksBuilder Configure(Action configure throw new InvalidOperationException($"A task with the name '{name}' has already been registered. Names are case insensitive."); } - opt.AddRegistration(name, tt); + opt.AddRegistration(name); }); Services.Configure(name, configure); diff --git a/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTasksHostOptions.cs b/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTasksHostOptions.cs index 817a199..0321e81 100644 --- a/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTasksHostOptions.cs +++ b/src/Tingle.PeriodicTasks/DependencyInjection/PeriodicTasksHostOptions.cs @@ -13,7 +13,7 @@ public class PeriodicTasksHostOptions /// Names must be case-insensitive because they are used to form lock names and the underlying distributed /// lock provider may not support case sensitivity. /// For example, using files for locks may fail because file names on Windows are case insensitive. - private readonly Dictionary registrations = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary registrations = new(StringComparer.OrdinalIgnoreCase); /// /// Gets or sets the prefix value for the lock names. @@ -64,7 +64,21 @@ public class PeriodicTasksHostOptions public PeriodicTaskIdFormat DefaultExecutionIdFormat { get; set; } = PeriodicTaskIdFormat.GuidNoDashes; /// The periodic tasks registered. - public IReadOnlyDictionary Registrations => registrations; + public IReadOnlyDictionary Registrations => registrations; - internal void AddRegistration(string name, [DynamicallyAccessedMembers(TrimmingHelper.Task)] Type type) => registrations.Add(name, type); + internal void AddRegistration<[DynamicallyAccessedMembers(TrimmingHelper.Task)] TTask>(string name) + => registrations.Add(name, new(typeof(TTask), typeof(IPeriodicTaskRunner))); +} + +/// Registration for a periodic task. +public readonly record struct PeriodicTaskTypeRegistration([DynamicallyAccessedMembers(TrimmingHelper.Task)] Type Type, [DynamicallyAccessedMembers(TrimmingHelper.Task)] Type RunnerType) +{ + /// Deconstructs the registration into its parts. + /// The type of the periodic task. + /// The type of the runner for the periodic task. + public void Deconstruct(out Type type, out Type runnerType) + { + type = Type; + runnerType = RunnerType; + } } diff --git a/src/Tingle.PeriodicTasks/Internal/PeriodicTaskRunnerCreator.cs b/src/Tingle.PeriodicTasks/Internal/PeriodicTaskRunnerCreator.cs index 0680c3e..1cb43c2 100644 --- a/src/Tingle.PeriodicTasks/Internal/PeriodicTaskRunnerCreator.cs +++ b/src/Tingle.PeriodicTasks/Internal/PeriodicTaskRunnerCreator.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using System.Diagnostics.CodeAnalysis; namespace Tingle.PeriodicTasks.Internal; @@ -11,19 +10,14 @@ internal class PeriodicTaskRunnerCreator(IServiceProvider provider, IOptions builder.AddTask(...)) when configuring your host."); } - return Create(type); + return Create(registration); } - public IPeriodicTaskRunner Create([DynamicallyAccessedMembers(TrimmingHelper.Task)] Type type) - { - var genericRunnerType = typeof(IPeriodicTaskRunner<>); - var runnerType = genericRunnerType.MakeGenericType(type); - return (IPeriodicTaskRunner)provider.GetRequiredService(runnerType); - } + public IPeriodicTaskRunner Create(PeriodicTaskTypeRegistration registration) => (IPeriodicTaskRunner)provider.GetRequiredService(registration.RunnerType); } diff --git a/src/Tingle.PeriodicTasks/Internal/PeriodicTasksHost.cs b/src/Tingle.PeriodicTasks/Internal/PeriodicTasksHost.cs index 5cf8b19..26a880a 100644 --- a/src/Tingle.PeriodicTasks/Internal/PeriodicTasksHost.cs +++ b/src/Tingle.PeriodicTasks/Internal/PeriodicTasksHost.cs @@ -23,10 +23,9 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) // create the tasks var tasks = new List(); - foreach (var registration in options.Registrations) + foreach (var (name, registration) in options.Registrations) { - var (name, type) = registration; - var runner = creator.Create(type); + var runner = creator.Create(registration); tasks.Add(runner.RunAsync(name, stoppingToken)); }