Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -128,25 +128,21 @@

<NetCoreAndroidTargetFrameworks
Condition=" '$(NetCoreAndroidTargetFrameworks)' == '' And '$(SupportsAndroidTargeting)' == 'true' ">
net9.0-android;
net10.0-android
</NetCoreAndroidTargetFrameworks>

<NetCoreIOSTargetFrameworks
Condition=" '$(NetCoreIOSTargetFrameworks)' == '' And '$(SupportsIOSTargeting)' == 'true' ">
net9.0-ios;
net10.0-ios
</NetCoreIOSTargetFrameworks>

<NetCoreMacCatalystTargetFrameworks
Condition=" '$(NetCoreMacCatalystTargetFrameworks)' == '' And '$(SupportsMacCatalystTargeting)' == 'true' ">
net9.0-maccatalyst;
net10.0-maccatalyst
</NetCoreMacCatalystTargetFrameworks>

<NetCoreMacOSTargetFrameworks
Condition=" '$(NetCoreMacOSTargetFrameworks)' == '' And '$(SupportsMacOSTargeting)' == 'true' ">
net9.0-macos;
net10.0-macos
</NetCoreMacOSTargetFrameworks>

Expand Down
156 changes: 81 additions & 75 deletions Directory.Packages.props

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions WorkloadRollback.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"microsoft.net.sdk.android": "36.1.43/10.0.100",
"microsoft.net.sdk.ios": "26.5.10284/10.0.100",
"microsoft.net.sdk.maccatalyst": "26.5.10284/10.0.100",
"microsoft.net.sdk.macos": "26.5.10284/10.0.100",
"microsoft.net.sdk.android": "36.1.69/10.0.100",
"microsoft.net.sdk.ios": "26.5.10301/10.0.100",
"microsoft.net.sdk.maccatalyst": "26.5.10301/10.0.100",
"microsoft.net.sdk.macos": "26.5.10301/10.0.100",
"microsoft.net.sdk.maui": "10.0.20/10.0.100",
"microsoft.net.sdk.tvos": "26.5.10284/10.0.100",
"microsoft.net.workload.mono.toolchain.current": "10.0.110/10.0.100",
"microsoft.net.workload.emscripten.current": "10.0.110/10.0.100",
"microsoft.net.workload.emscripten.net6": "10.0.110/10.0.100",
"microsoft.net.workload.emscripten.net7": "10.0.110/10.0.100",
"microsoft.net.workload.emscripten.net8": "10.0.110/10.0.100",
"microsoft.net.workload.emscripten.net9": "10.0.110/10.0.100",
"microsoft.net.workload.mono.toolchain.net6": "10.0.110/10.0.100",
"microsoft.net.workload.mono.toolchain.net7": "10.0.110/10.0.100",
"microsoft.net.workload.mono.toolchain.net8": "10.0.110/10.0.100",
"microsoft.net.workload.mono.toolchain.net9": "10.0.110/10.0.100"
"microsoft.net.sdk.tvos": "26.5.10301/10.0.100",
"microsoft.net.workload.mono.toolchain.current": "10.0.111/10.0.100",
"microsoft.net.workload.emscripten.current": "10.0.111/10.0.100",
"microsoft.net.workload.emscripten.net6": "10.0.111/10.0.100",
"microsoft.net.workload.emscripten.net7": "10.0.111/10.0.100",
"microsoft.net.workload.emscripten.net8": "10.0.111/10.0.100",
"microsoft.net.workload.emscripten.net9": "10.0.111/10.0.100",
"microsoft.net.workload.mono.toolchain.net6": "10.0.111/10.0.100",
"microsoft.net.workload.mono.toolchain.net7": "10.0.111/10.0.100",
"microsoft.net.workload.mono.toolchain.net8": "10.0.111/10.0.100",
"microsoft.net.workload.mono.toolchain.net9": "10.0.111/10.0.100"
}
8 changes: 4 additions & 4 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"sdk": {
"version": "10.0.302",
"version": "10.0.400",
"allowPrerelease": true,
"rollForward": "major"
},

"tools": {
"dotnet": "10.0.302",
"dotnet": "10.0.400",

"runtimes": {
"aspnetcore": [
"8.0.29",
"9.0.18"
"8.0.30",
"9.0.19"
]
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

<ItemGroup>
<ProjectReference Include="..\..\src\OpenIddict.EntityFramework\OpenIddict.EntityFramework.csproj" />
<ProjectReference Include="..\..\src\OpenIddict.Quartz\OpenIddict.Quartz.csproj" />
<ProjectReference Include="..\..\src\OpenIddict.Owin\OpenIddict.Owin.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
<PackageReference Include="Quartz.Extensions.Hosting" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFrameworkIdentifier)' == '.NETFramework' ">
Expand All @@ -26,6 +25,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" />
<PackageReference Include="Quartz.Extensions.Hosting" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
<PackageReference Include="Quartz.Extensions.Hosting" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFrameworkIdentifier)' == '.NETFramework' ">
Expand All @@ -29,6 +28,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" />
<PackageReference Include="Quartz.Extensions.Hosting" />
</ItemGroup>

</Project>
7 changes: 7 additions & 0 deletions src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Quartz" />
</ItemGroup>

<ItemGroup
Condition=" ('$(TargetFrameworkIdentifier)' == '.NETFramework') Or
('$(TargetFrameworkIdentifier)' == '.NETCoreApp' And $([MSBuild]::VersionLessThan($(TargetFrameworkVersion), '10.0'))) Or
('$(TargetFrameworkIdentifier)' == '.NETStandard') ">
<PackageReference Include="Quartz.Extensions.DependencyInjection" />
</ItemGroup>

Expand Down
27 changes: 1 addition & 26 deletions src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace OpenIddict.Quartz;
/// Contains the methods required to ensure that the OpenIddict Quartz.NET configuration is valid.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictQuartzConfiguration : IConfigureOptions<QuartzOptions>, IPostConfigureOptions<OpenIddictQuartzOptions>
public sealed class OpenIddictQuartzConfiguration : IPostConfigureOptions<OpenIddictQuartzOptions>
{
private readonly IServiceProvider _provider;

Expand All @@ -25,31 +25,6 @@ public sealed class OpenIddictQuartzConfiguration : IConfigureOptions<QuartzOpti
public OpenIddictQuartzConfiguration(IServiceProvider provider)
=> _provider = provider ?? throw new ArgumentNullException(nameof(provider));

/// <inheritdoc/>
public void Configure(QuartzOptions options)
{
ArgumentNullException.ThrowIfNull(options);

options.AddJob<OpenIddictQuartzJob>(builder =>
{
builder.StoreDurably()
.WithIdentity(OpenIddictQuartzJob.Identity)
.WithDescription(SR.GetResourceString(SR.ID8001));
});

options.AddTrigger(builder =>
{
// Note: this trigger uses a quite long interval (1 hour), which means it may be potentially never
// reached if the application is shut down or recycled. As such, this trigger is set up to fire
// between 1 and 10 minutes after the application starts to ensure the job is executed at least once.
builder.ForJob(OpenIddictQuartzJob.Identity)
.WithIdentity(SR.GetResourceString(SR.ID8004), SR.GetResourceString(SR.ID8005))
.WithSimpleSchedule(options => options.WithIntervalInHours(1).RepeatForever())
.WithDescription(SR.GetResourceString(SR.ID8002))
.StartAt(DateBuilder.FutureDate(new Random().Next(1, 10), IntervalUnit.Minute));
});
}

/// <inheritdoc/>
public void PostConfigure(string? name, OpenIddictQuartzOptions options)
{
Expand Down
36 changes: 29 additions & 7 deletions src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,38 @@ public static OpenIddictQuartzBuilder UseQuartz(this OpenIddictCoreBuilder build
{
ArgumentNullException.ThrowIfNull(builder);

builder.Services.AddQuartz();
// Note: the AddQuartz() method MUST only be called once to avoid adding multiple jobs and triggers.
if (!builder.Services.Any(static descriptor => descriptor.ServiceType == typeof(OpenIddictQuartzJob)))
{
builder.Services.AddQuartz(options =>
{
options.AddJob<OpenIddictQuartzJob>(static builder =>
{
builder.StoreDurably()
.WithIdentity(OpenIddictQuartzJob.Identity)
.WithDescription(SR.GetResourceString(SR.ID8001));
});

// The OpenIddict job is registered as a service to allow
// Quartz.NET's DI integration to resolve it from the DI.
builder.Services.TryAddTransient<OpenIddictQuartzJob>();
options.AddTrigger(static builder =>
{
// Note: this trigger uses a quite long interval (1 hour), which means it may be potentially never
// reached if the application is shut down or recycled. As such, this trigger is set up to fire
// between 1 and 10 minutes after the application starts to ensure the job is executed at least once.
builder.ForJob(OpenIddictQuartzJob.Identity)
.WithIdentity(SR.GetResourceString(SR.ID8004), SR.GetResourceString(SR.ID8005))
.WithSimpleSchedule(options => options.WithInterval(TimeSpan.FromHours(1)).RepeatForever())
.WithDescription(SR.GetResourceString(SR.ID8002))
.StartAt(TimeProvider.System.GetUtcNow() + TimeSpan.FromMinutes(new Random().Next(1, 10)));
});
});
}

// Note: TryAddEnumerable() is used here to ensure the initializers are registered only once.
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IConfigureOptions<QuartzOptions>, OpenIddictQuartzConfiguration>());
#if !NET10_0_OR_GREATER
// Note: unlike Quartz.NET 4.0+, Quartz.NET 3.x doesn't automatically register the job as a service.
builder.Services.TryAddTransient<OpenIddictQuartzJob>();
#endif

// Note: TryAddEnumerable() is used here to ensure the initializer is registered only once.
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IPostConfigureOptions<OpenIddictQuartzOptions>, OpenIddictQuartzConfiguration>());

Expand Down
39 changes: 20 additions & 19 deletions src/OpenIddict.Quartz/OpenIddictQuartzJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,21 @@ namespace OpenIddict.Quartz;
[DisallowConcurrentExecution, EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictQuartzJob : IJob
{
private readonly IOptionsMonitor<OpenIddictQuartzOptions> _options;
private readonly IServiceProvider _provider;

#if !NET10_0_OR_GREATER
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictQuartzJob"/> class.
/// </summary>
public OpenIddictQuartzJob() => throw new InvalidOperationException(SR.GetResourceString(SR.ID0082));
#endif

/// <summary>
/// Creates a new instance of the <see cref="OpenIddictQuartzJob"/> class.
/// </summary>
/// <param name="options">The OpenIddict Quartz.NET options.</param>
/// <param name="provider">The service provider.</param>
public OpenIddictQuartzJob(IOptionsMonitor<OpenIddictQuartzOptions> options, IServiceProvider provider)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
public OpenIddictQuartzJob(IServiceProvider provider)
=> _provider = provider ?? throw new ArgumentNullException(nameof(provider));

/// <summary>
/// Gets the default identity assigned to this job.
Expand All @@ -43,20 +40,24 @@ public OpenIddictQuartzJob(IOptionsMonitor<OpenIddictQuartzOptions> options, ISe
group: SR.GetResourceString(SR.ID8005));

/// <inheritdoc/>
#if NET10_0_OR_GREATER
public async ValueTask Execute(IJobExecutionContext context, CancellationToken cancellationToken = default)
#else
public async Task Execute(IJobExecutionContext context)
#endif
{
ArgumentNullException.ThrowIfNull(context);

List<Exception>? exceptions = null;

// Note: this job is registered as a transient service. As such, it cannot directly depend on scoped services
// like the core managers. To work around this limitation, a scope is manually created for each invocation.
await using var scope = _provider.CreateAsyncScope();

var options = scope.ServiceProvider.GetRequiredService<IOptionsMonitor<OpenIddictQuartzOptions>>().CurrentValue;

// Important: since authorizations that still have tokens attached are never
// pruned, the tokens MUST be deleted before deleting the authorizations.

if (!_options.CurrentValue.DisableTokenPruning)
if (!options.DisableTokenPruning)
{
var manager = scope.ServiceProvider.GetService<IOpenIddictTokenManager>() ??
throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278)))
Expand All @@ -66,7 +67,7 @@ public async Task Execute(IJobExecutionContext context)
UnscheduleFiringTrigger = true
};

var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumTokenLifespan;
var threshold = options.TimeProvider.GetUtcNow() - options.MinimumTokenLifespan;

try
{
Expand All @@ -88,20 +89,20 @@ public async Task Execute(IJobExecutionContext context)
// occurred while trying to prune the entities. In this case, add the inner exceptions to the collection.
catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= [];
exceptions ??= new List<Exception>(capacity: exception.InnerExceptions.Count);
exceptions.AddRange(exception.InnerExceptions);
}

// Other non-fatal exceptions are assumed to be transient and are added to the exceptions collection
// to be re-thrown later (typically, at the very end of this job, as an AggregateException).
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= [];
exceptions ??= new List<Exception>(capacity: 1);
exceptions.Add(exception);
}
}

if (!_options.CurrentValue.DisableAuthorizationPruning)
if (!options.DisableAuthorizationPruning)
{
var manager = scope.ServiceProvider.GetService<IOpenIddictAuthorizationManager>() ??
throw new JobExecutionException(new InvalidOperationException(SR.GetResourceString(SR.ID0278)))
Expand All @@ -111,7 +112,7 @@ public async Task Execute(IJobExecutionContext context)
UnscheduleFiringTrigger = true
};

var threshold = _options.CurrentValue.TimeProvider.GetUtcNow() - _options.CurrentValue.MinimumAuthorizationLifespan;
var threshold = options.TimeProvider.GetUtcNow() - options.MinimumAuthorizationLifespan;

try
{
Expand All @@ -133,25 +134,25 @@ public async Task Execute(IJobExecutionContext context)
// occurred while trying to prune the entities. In this case, add the inner exceptions to the collection.
catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= [];
exceptions ??= new List<Exception>(capacity: exception.InnerExceptions.Count);
exceptions.AddRange(exception.InnerExceptions);
}

// Other non-fatal exceptions are assumed to be transient and are added to the exceptions collection
// to be re-thrown later (typically, at the very end of this job, as an AggregateException).
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= [];
exceptions ??= new List<Exception>(capacity: 1);
exceptions.Add(exception);
}
}

if (exceptions is not null)
if (exceptions is { Count: > 0 })
{
throw new JobExecutionException(new AggregateException(exceptions))
{
// Only refire the job if the maximum refire count set in the options wasn't reached.
RefireImmediately = context.RefireCount < _options.CurrentValue.MaximumRefireCount
RefireImmediately = context.RefireCount < options.MaximumRefireCount
};
}
}
Expand Down
44 changes: 0 additions & 44 deletions test/OpenIddict.Quartz.Tests/OpenIddictQuartzConfigurationTests.cs

This file was deleted.

Loading