diff --git a/changelog.md b/changelog.md index f9e38df66..ba1e75830 100644 --- a/changelog.md +++ b/changelog.md @@ -8,7 +8,7 @@ * `TryGetString` method added to JobDataMap (#2125) * Add NET 8.0 targeting for examples, tests and integration projects (#2192) * Upgrade TimeZoneConverter to version 6.1.0 (#2194) - * Improve trimming compatibility #2195 + * Improve trimming compatibility (#2195) * FIXES * JobDataMap `TryGetXXX` methods will now correctly return true/false if a key value can be retrieved (or not) (#2125) @@ -17,6 +17,7 @@ * DailyCalendar should use same time zone offset for all checks (#2113) * SendMailJob will now throw JobExecutionException on BuildMessage construction failure due to missing mandatory params. (#2126) * JobInterruptMonitorPlugin should tolerate missing JobDataMapKeyAutoInterruptable (#2191) + * XMLSchedulingDataProcessorPlugin not using custom TypeLoader #2131 ## Release 3.7.0, Aug 4 2023 diff --git a/src/Quartz.Examples.AspNetCore/CustomTypeLoader.cs b/src/Quartz.Examples.AspNetCore/CustomTypeLoader.cs new file mode 100644 index 000000000..6d1dba872 --- /dev/null +++ b/src/Quartz.Examples.AspNetCore/CustomTypeLoader.cs @@ -0,0 +1,27 @@ +using System; + +using Microsoft.Extensions.Logging; + +using Quartz.Spi; + +namespace Quartz.Examples.AspNetCore; + +public class CustomTypeLoader : ITypeLoadHelper +{ + private readonly ILogger logger; + + public CustomTypeLoader(ILogger logger) + { + this.logger = logger; + } + + public void Initialize() + { + } + + public Type? LoadType(string? name) + { + logger.LogInformation("Requested to load type {TypeName}", name); + return Type.GetType(name!); + } +} diff --git a/src/Quartz.Examples.AspNetCore/Startup.cs b/src/Quartz.Examples.AspNetCore/Startup.cs index 8c70b0e44..f65012368 100644 --- a/src/Quartz.Examples.AspNetCore/Startup.cs +++ b/src/Quartz.Examples.AspNetCore/Startup.cs @@ -101,6 +101,9 @@ public void ConfigureServices(IServiceCollection services) q.UseInMemoryStore(); q.UseDefaultThreadPool(maxConcurrency: 10); + // you could use custom too + q.UseTypeLoader(); + // quickest way to create a job with single trigger is to use ScheduleJob q.ScheduleJob(trigger => trigger .WithIdentity("Combined Configuration Trigger") diff --git a/src/Quartz.Extensions.DependencyInjection/ServiceCollectionQuartzConfigurator.cs b/src/Quartz.Extensions.DependencyInjection/ServiceCollectionQuartzConfigurator.cs index f90c8c3bf..b54fdce3d 100644 --- a/src/Quartz.Extensions.DependencyInjection/ServiceCollectionQuartzConfigurator.cs +++ b/src/Quartz.Extensions.DependencyInjection/ServiceCollectionQuartzConfigurator.cs @@ -9,7 +9,7 @@ namespace Quartz { - internal sealed class ServiceCollectionQuartzConfigurator : IServiceCollectionQuartzConfigurator + internal sealed class ServiceCollectionQuartzConfigurator : IServiceCollectionQuartzConfigurator, IContainerConfigurationSupport { private readonly IServiceCollection services; private readonly SchedulerBuilder schedulerBuilder; @@ -257,5 +257,18 @@ public void AddTriggerListener< services.AddSingleton(new TriggerListenerConfiguration(typeof(T), matchers)); services.AddSingleton(implementationFactory); } + + public void RegisterSingleton< + TService, +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] +#endif + TImplementation>() + where TService : class + where TImplementation : class, TService + { + + services.AddSingleton(); + } } } \ No newline at end of file diff --git a/src/Quartz.Plugins/Plugin/Xml/XMLSchedulingDataProcessorPlugin.cs b/src/Quartz.Plugins/Plugin/Xml/XMLSchedulingDataProcessorPlugin.cs index 0d956a5aa..7edff8735 100644 --- a/src/Quartz.Plugins/Plugin/Xml/XMLSchedulingDataProcessorPlugin.cs +++ b/src/Quartz.Plugins/Plugin/Xml/XMLSchedulingDataProcessorPlugin.cs @@ -64,22 +64,26 @@ public class XMLSchedulingDataProcessorPlugin : ISchedulerPlugin, IFileScanListe /// /// Initializes a new instance of the class. /// - public XMLSchedulingDataProcessorPlugin() + public XMLSchedulingDataProcessorPlugin() : this(new SimpleTypeLoadHelper()) { - Log = LogProvider.GetLogger(typeof (XMLSchedulingDataProcessorPlugin)); } /// - /// Gets the log. + /// Initializes a new instance of the class. /// - /// The log. + public XMLSchedulingDataProcessorPlugin(ITypeLoadHelper typeLoadHelper) + { + Log = LogProvider.GetLogger(typeof (XMLSchedulingDataProcessorPlugin)); + TypeLoadHelper = typeLoadHelper; + } + private ILog Log { get; } public string Name { get; private set; } = null!; public IScheduler Scheduler { get; private set; } = null!; - protected ITypeLoadHelper TypeLoadHelper { get; private set; } = null!; + protected ITypeLoadHelper TypeLoadHelper { get; private set; } /// /// Comma separated list of file names (with paths) to the XML files that should be read. @@ -131,8 +135,6 @@ public virtual async Task Initialize( { Name = pluginName; Scheduler = scheduler; - TypeLoadHelper = new SimpleTypeLoadHelper(); - TypeLoadHelper.Initialize(); Log.Info("Registering Quartz Job Initialization Plug-in."); diff --git a/src/Quartz.Plugins/PluginConfigurationExtensions.cs b/src/Quartz.Plugins/PluginConfigurationExtensions.cs index ac5386bdd..4245efd24 100644 --- a/src/Quartz.Plugins/PluginConfigurationExtensions.cs +++ b/src/Quartz.Plugins/PluginConfigurationExtensions.cs @@ -9,10 +9,18 @@ namespace Quartz { public static class PluginConfigurationExtensions { - public static T UseXmlSchedulingConfiguration( + public static T UseXmlSchedulingConfiguration< +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] +#endif + T>( this T configurer, Action configure) where T : IPropertyConfigurationRoot { + if (configurer is IContainerConfigurationSupport containerConfigurationSupport) + { + containerConfigurationSupport.RegisterSingleton(); + } configurer.SetProperty("quartz.plugin.xml.type", typeof(XMLSchedulingDataProcessorPlugin).AssemblyQualifiedNameWithoutVersion()); configure.Invoke(new XmlSchedulingOptions(configurer)); return configurer; @@ -21,10 +29,18 @@ public static T UseXmlSchedulingConfiguration( /// /// Configures into use. /// - public static T UseJobAutoInterrupt( + public static T UseJobAutoInterrupt< +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] +#endif + T>( this T configurer, Action? configure = null) where T : IPropertyConfigurationRoot { + if (configurer is IContainerConfigurationSupport containerConfigurationSupport) + { + containerConfigurationSupport.RegisterSingleton(); + } configurer.SetProperty("quartz.plugin.jobAutoInterrupt.type", typeof(JobInterruptMonitorPlugin).AssemblyQualifiedNameWithoutVersion()); configure?.Invoke(new JobAutoInterruptOptions(configurer)); return configurer; diff --git a/src/Quartz/IPropertyConfigurer.cs b/src/Quartz/IPropertyConfigurer.cs index 1838926e6..5e7da7310 100644 --- a/src/Quartz/IPropertyConfigurer.cs +++ b/src/Quartz/IPropertyConfigurer.cs @@ -24,4 +24,16 @@ public interface IPropertySetter public interface IPropertyConfigurationRoot : IPropertySetter { } + + internal interface IContainerConfigurationSupport : IPropertyConfigurer, IPropertyConfigurationRoot + { + void RegisterSingleton< + TService, +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] +#endif + TImplementation>() + where TService : class + where TImplementation : class, TService; + } } \ No newline at end of file diff --git a/src/Quartz/Impl/StdSchedulerFactory.cs b/src/Quartz/Impl/StdSchedulerFactory.cs index ea0a8384d..84eb09b51 100644 --- a/src/Quartz/Impl/StdSchedulerFactory.cs +++ b/src/Quartz/Impl/StdSchedulerFactory.cs @@ -793,7 +793,10 @@ private async Task Instantiate() ISchedulerPlugin plugin; try { - plugin = InstantiateType(LoadType(plugInType)); + var pluginTypeType = LoadType(plugInType) ?? throw new ConfigurationException($"Could not load plugin type {plugInType}"); + // we need to use concrete types to resolve correct one + var method = GetType().GetMethod(nameof(InstantiateType), BindingFlags.Instance | BindingFlags.NonPublic)!.MakeGenericMethod(pluginTypeType); + plugin = (ISchedulerPlugin) method.Invoke(this, new [] { pluginTypeType })!; } catch (Exception e) {