diff --git a/Directory.Packages.props b/Directory.Packages.props
index c7c47642..968d4985 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -15,8 +15,8 @@
-
-
+
+
diff --git a/NuGet.config b/NuGet.config
index 7c791c5c..a37acc28 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -1,7 +1,6 @@
-
diff --git a/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj b/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
index 1cbfb07a..bd1fc2e3 100644
--- a/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
+++ b/src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
@@ -3,7 +3,6 @@
net461;netcoreapp2.1;netcoreapp3.1;netstandard2.0;netstandard2.1
enable
- false
diff --git a/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs b/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs
new file mode 100644
index 00000000..abd12daa
--- /dev/null
+++ b/src/OpenIddict.Quartz/OpenIddictQuartzConfiguration.cs
@@ -0,0 +1,46 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ * See https://github.com/openiddict/openiddict-core for more information concerning
+ * the license and the contributors participating to this project.
+ */
+
+using System;
+using Microsoft.Extensions.Options;
+using Quartz;
+using SR = OpenIddict.Abstractions.OpenIddictResources;
+
+namespace OpenIddict.Quartz
+{
+ ///
+ /// Contains the methods required to ensure that the OpenIddict Quartz.NET configuration is valid.
+ ///
+ public class OpenIddictQuartzConfiguration : IConfigureOptions
+ {
+ ///
+ public void Configure(QuartzOptions options)
+ {
+ if (options is null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ options.AddJob(builder =>
+ {
+ builder.StoreDurably()
+ .WithIdentity(OpenIddictQuartzJob.Identity)
+ .WithDescription(SR.GetResourceString(SR.ID8000));
+ });
+
+ 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 2 minutes after the application starts to ensure it's executed at least once.
+ builder.ForJob(OpenIddictQuartzJob.Identity)
+ .WithSimpleSchedule(options => options.WithIntervalInHours(1).RepeatForever())
+ .WithDescription(SR.GetResourceString(SR.ID8001))
+ .StartAt(DateBuilder.FutureDate(2, IntervalUnit.Minute));
+ });
+ }
+ }
+}
diff --git a/src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs b/src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs
index 8883ed56..d2d3d501 100644
--- a/src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs
+++ b/src/OpenIddict.Quartz/OpenIddictQuartzExtensions.cs
@@ -5,11 +5,10 @@
*/
using System;
-using System.Linq;
using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Options;
using OpenIddict.Quartz;
using Quartz;
-using SR = OpenIddict.Abstractions.OpenIddictResources;
namespace Microsoft.Extensions.DependencyInjection
{
@@ -31,44 +30,15 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(builder));
}
- // Warning: the AddQuartz() method is deliberately not used as it's not idempotent.
- // Calling it at this point may override user-defined services (e.g Quartz DI support).
+ builder.Services.AddQuartz();
+ // The OpenIddict job is registered as a service to allow
+ // Quartz.NET's DI integration to resolve it from the DI.
builder.Services.TryAddTransient();
- // To ensure this method can be safely called multiple times, the job details
- // of the OpenIddict job are only added if no existing IJobDetail instance
- // pointing to OpenIddictQuartzJob was already registered in the DI container.
- if (!builder.Services.Any(descriptor => descriptor.ServiceType == typeof(IJobDetail) &&
- descriptor.ImplementationInstance is IJobDetail job &&
- job.Key.Equals(OpenIddictQuartzJob.Identity)))
- {
- builder.Services.AddSingleton(
- JobBuilder.Create()
- .StoreDurably()
- .WithIdentity(OpenIddictQuartzJob.Identity)
- .WithDescription(SR.GetResourceString(SR.ID8000))
- .Build());
- }
-
- // To ensure this method can be safely called multiple times, the trigger details
- // of the OpenIddict job are only added if no existing ITrigger instance
- // pointing to OpenIddictQuartzJob was already registered in the DI container.
- if (!builder.Services.Any(descriptor => descriptor.ServiceType == typeof(ITrigger) &&
- descriptor.ImplementationInstance is ITrigger trigger &&
- trigger.JobKey.Equals(OpenIddictQuartzJob.Identity)))
- {
- // 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 2 minutes after the application starts to ensure it's executed at least once.
- builder.Services.AddSingleton(
- TriggerBuilder.Create()
- .ForJob(OpenIddictQuartzJob.Identity)
- .WithSimpleSchedule(options => options.WithIntervalInHours(1).RepeatForever())
- .WithDescription(SR.GetResourceString(SR.ID8001))
- .StartAt(DateBuilder.FutureDate(2, IntervalUnit.Minute))
- .Build());
- }
+ // Note: TryAddEnumerable() is used here to ensure the initializer is registered only once.
+ builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
+ IConfigureOptions, OpenIddictQuartzConfiguration>());
return new OpenIddictQuartzBuilder(builder.Services);
}
diff --git a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzConfigurationTests.cs b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzConfigurationTests.cs
new file mode 100644
index 00000000..37bd3bf8
--- /dev/null
+++ b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzConfigurationTests.cs
@@ -0,0 +1,38 @@
+using Quartz;
+using Xunit;
+
+namespace OpenIddict.Quartz.Tests
+{
+ public class OpenIddictQuartzConfigurationTests
+ {
+ [Fact]
+ public void UseQuartz_RegistersJobDetails()
+ {
+ // Arrange
+ var options = new QuartzOptions();
+ var configuration = new OpenIddictQuartzConfiguration();
+
+ // Act
+ configuration.Configure(options);
+
+ // Assert
+ // TODO: uncomment when JobDetails and Triggers are publicly exposed.
+ // Assert.Contains(options.JobDetails, job => job.Key.Equals(OpenIddictQuartzJob.Identity));
+ }
+
+ [Fact]
+ public void UseQuartz_RegistersTriggerDetails()
+ {
+ // Arrange
+ var options = new QuartzOptions();
+ var configuration = new OpenIddictQuartzConfiguration();
+
+ // Act
+ configuration.Configure(options);
+
+ // Assert
+ // TODO: uncomment when JobDetails and Triggers are publicly exposed.
+ // Assert.Contains(options.Triggers, trigger => trigger.JobKey.Equals(OpenIddictQuartzJob.Identity));
+ }
+ }
+}
diff --git a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzExtensionsTests.cs b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzExtensionsTests.cs
index 7ec1dc5d..127e27d2 100644
--- a/test/OpenIddict.Quartz.Tests/OpenIddictQuartzExtensionsTests.cs
+++ b/test/OpenIddict.Quartz.Tests/OpenIddictQuartzExtensionsTests.cs
@@ -1,5 +1,6 @@
using System;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
using Quartz;
using Xunit;
@@ -48,38 +49,6 @@ namespace OpenIddict.Quartz.Tests
service.Lifetime == ServiceLifetime.Transient);
}
- [Fact]
- public void UseQuartz_RegistersJobDetails()
- {
- // Arrange
- var services = new ServiceCollection();
- var builder = new OpenIddictCoreBuilder(services);
-
- // Act
- builder.UseQuartz();
-
- // Assert
- Assert.Contains(services, service => service.ServiceType == typeof(IJobDetail) &&
- service.ImplementationInstance is IJobDetail job &&
- job.Key.Equals(OpenIddictQuartzJob.Identity));
- }
-
- [Fact]
- public void UseQuartz_RegistersTriggerDetails()
- {
- // Arrange
- var services = new ServiceCollection();
- var builder = new OpenIddictCoreBuilder(services);
-
- // Act
- builder.UseQuartz();
-
- // Assert
- Assert.Contains(services, service => service.ServiceType == typeof(ITrigger) &&
- service.ImplementationInstance is ITrigger trigger &&
- trigger.JobKey.Equals(OpenIddictQuartzJob.Identity));
- }
-
[Fact]
public void UseQuartz_CanBeSafelyInvokedMultipleTimes()
{
@@ -93,13 +62,13 @@ namespace OpenIddict.Quartz.Tests
builder.UseQuartz();
// Assert
- Assert.Single(services, service => service.ServiceType == typeof(IJobDetail) &&
- service.ImplementationInstance is IJobDetail job &&
- job.Key.Equals(OpenIddictQuartzJob.Identity));
+ Assert.Single(services, service => service.ServiceType == typeof(OpenIddictQuartzJob) &&
+ service.ImplementationType == typeof(OpenIddictQuartzJob) &&
+ service.Lifetime == ServiceLifetime.Transient);
- Assert.Single(services, service => service.ServiceType == typeof(ITrigger) &&
- service.ImplementationInstance is ITrigger trigger &&
- trigger.JobKey.Equals(OpenIddictQuartzJob.Identity));
+ Assert.Single(services, service => service.ServiceType == typeof(IConfigureOptions) &&
+ service.ImplementationType == typeof(OpenIddictQuartzConfiguration) &&
+ service.Lifetime == ServiceLifetime.Singleton);
}
}
}