Class QuartzServiceCollectionExtensions
- Namespace
- Quartz
- Assembly
- Quartz.dll
Registers Quartz schedulers, and the hosted service that runs them, into an application's container.
public static class QuartzServiceCollectionExtensions
- Inheritance
-
QuartzServiceCollectionExtensions
- Inherited Members
Remarks
The other half of this class lives beside the hosted service it registers, in
Hosting/QuartzServiceCollectionExtensions.cs. What a scheduler carries — jobs,
triggers, calendars — is added through QuartzBuilderExtensions, which extends
IQuartzBuilder rather than IServiceCollection.
Methods
AddQuartz(IServiceCollection, IConfiguration, Action<IQuartzBuilder>?)
Registers a Quartz scheduler from a configuration section.
public static IServiceCollection AddQuartz(this IServiceCollection services, IConfiguration configuration, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionconfigurationIConfigurationconfigureAction<IQuartzBuilder>
Returns
Remarks
Hierarchical sections such as Scheduler and ThreadPool bind onto the typed options
directly. Flat quartz.* keys are still accepted and mean the same thing. Several
schedulers described by one section are registered with
AddQuartzSchedulers(IServiceCollection, IConfiguration, Action<IQuartzBuilder>?).
A scheduler is described by six things, applied in this order — which is what decides who wins when two of them say something about the same setting:
-
The flat
quartz.*properties are recorded in Properties, so the parts that read the property bag directly — plugins, execution limits — can see them. - Those properties are translated into typed options.
-
Properties contributed later by configuring QuartzOptions are translated too, which
is what makes
services.Configure<QuartzOptions>equivalent to passing them here. -
The
configurecallback runs. Options are last-wins, so anything it sets is applied over the property-derived values: configuration written in code beats a string. -
The implementations the properties name — a job store type, a thread pool type, a serializer —
are registered. Registration is first-wins, so this comes after the callback: a store
chosen by
UsePersistentStorehas to beat a leftoverquartz.jobStore.typefrom an old configuration file. Code beats strings in both directions, opposite orders notwithstanding. - Quartz's own defaults are registered last, so an explicitly configured job store, thread pool or serializer is never beaten to the registration by the fallback it was meant to replace.
The scheduler this registers is the container's unkeyed IScheduler, which is what
GetRequiredService<IScheduler>() answers with. Registering it when something else
already owns that slot throws an InvalidOperationException rather than quietly
leaving "the scheduler" meaning the other one; AddQuartzHttpClient is the one in the box
that takes it. The other order is fine and needs no thought: AddQuartz() followed by
AddQuartzHttpClient(…) leaves the local default scheduler unkeyed and the remote one
reachable as GetRequiredKeyedService<IScheduler>(schedulerName).
AddQuartz(IServiceCollection, Action<IQuartzBuilder>?)
Registers a Quartz scheduler.
public static IServiceCollection AddQuartz(this IServiceCollection services, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionconfigureAction<IQuartzBuilder>
Returns
Remarks
Hierarchical sections such as Scheduler and ThreadPool bind onto the typed options
directly. Flat quartz.* keys are still accepted and mean the same thing. Several
schedulers described by one section are registered with
AddQuartzSchedulers(IServiceCollection, IConfiguration, Action<IQuartzBuilder>?).
A scheduler is described by six things, applied in this order — which is what decides who wins when two of them say something about the same setting:
-
The flat
quartz.*properties are recorded in Properties, so the parts that read the property bag directly — plugins, execution limits — can see them. - Those properties are translated into typed options.
-
Properties contributed later by configuring QuartzOptions are translated too, which
is what makes
services.Configure<QuartzOptions>equivalent to passing them here. -
The
configurecallback runs. Options are last-wins, so anything it sets is applied over the property-derived values: configuration written in code beats a string. -
The implementations the properties name — a job store type, a thread pool type, a serializer —
are registered. Registration is first-wins, so this comes after the callback: a store
chosen by
UsePersistentStorehas to beat a leftoverquartz.jobStore.typefrom an old configuration file. Code beats strings in both directions, opposite orders notwithstanding. - Quartz's own defaults are registered last, so an explicitly configured job store, thread pool or serializer is never beaten to the registration by the fallback it was meant to replace.
The scheduler this registers is the container's unkeyed IScheduler, which is what
GetRequiredService<IScheduler>() answers with. Registering it when something else
already owns that slot throws an InvalidOperationException rather than quietly
leaving "the scheduler" meaning the other one; AddQuartzHttpClient is the one in the box
that takes it. The other order is fine and needs no thought: AddQuartz() followed by
AddQuartzHttpClient(…) leaves the local default scheduler unkeyed and the remote one
reachable as GetRequiredKeyedService<IScheduler>(schedulerName).
AddQuartz(IServiceCollection, IEnumerable<KeyValuePair<string, string?>>, Action<IQuartzBuilder>?)
Registers a Quartz scheduler, seeded with flat quartz.* properties.
public static IServiceCollection AddQuartz(this IServiceCollection services, IEnumerable<KeyValuePair<string, string?>> properties, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionThe service collection to register into.
propertiesIEnumerable<KeyValuePair<string, string>>The flat
quartz.*properties, in the shape every dictionary already has — a Dictionary<TKey, TValue>, an IReadOnlyDictionary<TKey, TValue> and Properties all go in without a conversion step. They are checked against the keys Quartz reads, as they are on the standalone builder, so a misspelling — or a key 4.0 stopped reading — is reported rather than silently ignored. Setquartz.checkConfigurationto false to allow keys of your own.configureAction<IQuartzBuilder>Configures the scheduler.
Returns
Remarks
Hierarchical sections such as Scheduler and ThreadPool bind onto the typed options
directly. Flat quartz.* keys are still accepted and mean the same thing. Several
schedulers described by one section are registered with
AddQuartzSchedulers(IServiceCollection, IConfiguration, Action<IQuartzBuilder>?).
A scheduler is described by six things, applied in this order — which is what decides who wins when two of them say something about the same setting:
-
The flat
quartz.*properties are recorded in Properties, so the parts that read the property bag directly — plugins, execution limits — can see them. - Those properties are translated into typed options.
-
Properties contributed later by configuring QuartzOptions are translated too, which
is what makes
services.Configure<QuartzOptions>equivalent to passing them here. -
The
configurecallback runs. Options are last-wins, so anything it sets is applied over the property-derived values: configuration written in code beats a string. -
The implementations the properties name — a job store type, a thread pool type, a serializer —
are registered. Registration is first-wins, so this comes after the callback: a store
chosen by
UsePersistentStorehas to beat a leftoverquartz.jobStore.typefrom an old configuration file. Code beats strings in both directions, opposite orders notwithstanding. - Quartz's own defaults are registered last, so an explicitly configured job store, thread pool or serializer is never beaten to the registration by the fallback it was meant to replace.
The scheduler this registers is the container's unkeyed IScheduler, which is what
GetRequiredService<IScheduler>() answers with. Registering it when something else
already owns that slot throws an InvalidOperationException rather than quietly
leaving "the scheduler" meaning the other one; AddQuartzHttpClient is the one in the box
that takes it. The other order is fine and needs no thought: AddQuartz() followed by
AddQuartzHttpClient(…) leaves the local default scheduler unkeyed and the remote one
reachable as GetRequiredKeyedService<IScheduler>(schedulerName).
AddQuartz(IServiceCollection, NameValueCollection, Action<IQuartzBuilder>?)
Registers a Quartz scheduler, seeded with flat quartz.* properties held in a
NameValueCollection.
public static IServiceCollection AddQuartz(this IServiceCollection services, NameValueCollection properties, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionThe service collection to register into.
propertiesNameValueCollectionThe flat
quartz.*properties.configureAction<IQuartzBuilder>Configures the scheduler.
Returns
Remarks
A NameValueCollection is what a caller migrating from 3.x already holds — it is what
StdSchedulerFactory took — so it stays a single call. Everything else about it is
AddQuartz(IServiceCollection, IEnumerable<KeyValuePair<string, string?>>, Action<IQuartzBuilder>?),
which this forwards to.
AddQuartz(IServiceCollection, string, IConfiguration, Action<IQuartzBuilder>?)
Registers a named Quartz scheduler from a configuration section.
public static IServiceCollection AddQuartz(this IServiceCollection services, string name, IConfiguration configuration, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionnamestringconfigurationIConfigurationconfigureAction<IQuartzBuilder>
Returns
AddQuartz(IServiceCollection, string, Action<IQuartzBuilder>?)
Registers a named Quartz scheduler, so several independent schedulers can share a container.
public static IServiceCollection AddQuartz(this IServiceCollection services, string name, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionnamestringconfigureAction<IQuartzBuilder>
Returns
Remarks
The name is the scheduler's instance name, the key its components are registered under, and the name of its options, so its registrations and its configuration always agree.
AddQuartz(IServiceCollection, string, IEnumerable<KeyValuePair<string, string?>>, Action<IQuartzBuilder>?)
Registers a named Quartz scheduler, seeded with flat quartz.* properties.
public static IServiceCollection AddQuartz(this IServiceCollection services, string name, IEnumerable<KeyValuePair<string, string?>> properties, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionnamestringpropertiesIEnumerable<KeyValuePair<string, string>>The flat
quartz.*properties, in the shape every dictionary already has — a Dictionary<TKey, TValue>, an IReadOnlyDictionary<TKey, TValue> and Properties all go in without a conversion step. They are checked against the keys Quartz reads, as they are on the standalone builder, so a misspelling — or a key 4.0 stopped reading — is reported rather than silently ignored. Setquartz.checkConfigurationto false to allow keys of your own.configureAction<IQuartzBuilder>
Returns
AddQuartz(IServiceCollection, string, NameValueCollection, Action<IQuartzBuilder>?)
Registers a named Quartz scheduler, seeded with flat quartz.* properties held in a
NameValueCollection.
public static IServiceCollection AddQuartz(this IServiceCollection services, string name, NameValueCollection properties, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionnamestringpropertiesNameValueCollectionconfigureAction<IQuartzBuilder>
Returns
Remarks
A NameValueCollection is what a caller migrating from 3.x already holds — it is what
StdSchedulerFactory took — so it stays a single call. Everything else about it is
AddQuartz(IServiceCollection, IEnumerable<KeyValuePair<string, string?>>, Action<IQuartzBuilder>?),
which this forwards to.
AddQuartzHostedService(IServiceCollection, Action<QuartzHostedServiceOptions>?)
Adds a QuartzHostedService to the IServiceCollection, which starts and stops every scheduler in the container with the application.
public static IServiceCollection AddQuartzHostedService(this IServiceCollection services, Action<QuartzHostedServiceOptions>? configure = null)
Parameters
servicesIServiceCollectionThe IServiceCollection.
configureAction<QuartzHostedServiceOptions>A delegate that is used to configure an QuartzHostedServiceOptions.
Returns
Remarks
The options configured here apply to every scheduler, which is what they have always meant. One scheduler that has to differ says so with AddQuartzHostedService(IServiceCollection, string, Action<QuartzHostedServiceOptions>?).
AddQuartzHostedService(IServiceCollection, string, Action<QuartzHostedServiceOptions>?)
Configures how a named scheduler is started and stopped by the hosted service.
public static IServiceCollection AddQuartzHostedService(this IServiceCollection services, string schedulerName, Action<QuartzHostedServiceOptions>? configure = null)
Parameters
servicesIServiceCollectionThe IServiceCollection.
schedulerNamestringThe name the scheduler was registered under with
AddQuartz(name, …).configureAction<QuartzHostedServiceOptions>A delegate that is used to configure an QuartzHostedServiceOptions.
Returns
Remarks
The hosted service starts every scheduler in the container; this says how one of them is treated. A scheduler that should wait for application startup while another does not, or that needs longer to drain on shutdown, is configured here. It refines the settings shared by every scheduler, whichever order the two calls are made in.
AddQuartzHostedService<T>(IServiceCollection, Action<QuartzHostedServiceOptions>?)
Adds a hosted service of your own deriving from QuartzHostedService.
public static IServiceCollection AddQuartzHostedService<T>(this IServiceCollection services, Action<QuartzHostedServiceOptions>? configure = null) where T : QuartzHostedService
Parameters
servicesIServiceCollectionThe IServiceCollection.
configureAction<QuartzHostedServiceOptions>A delegate that is used to configure an QuartzHostedServiceOptions.
Returns
Type Parameters
TType extending the QuartzHostedService class.
Remarks
The options configured here apply to every scheduler, which is what they have always meant. One scheduler that has to differ says so with AddQuartzHostedService(IServiceCollection, string, Action<QuartzHostedServiceOptions>?).
AddQuartzSchedulers(IServiceCollection, IConfiguration, Action<IQuartzBuilder>?)
Registers one named Quartz scheduler per child of the section's Schedulers sub-section.
public static IServiceCollection AddQuartzSchedulers(this IServiceCollection services, IConfiguration configuration, Action<IQuartzBuilder>? configure = null)
Parameters
servicesIServiceCollectionThe service collection to register into.
configurationIConfigurationThe Quartz configuration section, containing a
Schedulerssub-section.configureAction<IQuartzBuilder>Applied to every scheduler described by the section.
Returns
Remarks
Each child's key is the scheduler's name, and its contents are that scheduler's configuration —
exactly what AddQuartz(name, section) would be given. The fan-out is its own method
because registering several schedulers is a different act from registering one, and reading it
out of the shape of a configuration file made AddQuartz mean two things depending on data
it was handed.
The section is a parameter because this receiver has no configuration of its own, which is the
rule every method here follows: a service collection is handed its configuration and never goes
looking for one, so AddQuartz(configure) means a scheduler configured entirely in code
rather than one that quietly reads whatever IConfiguration the container holds. On
a host application builder, which does hold configuration, this is
builder.AddQuartzSchedulers(…) and takes no section — the same difference
AddQuartz has between the two receivers.
ConfigureAllQuartzSchedulers(IServiceCollection, Action<IQuartzBuilder>)
Configures every Quartz scheduler in the container, whenever it was registered.
public static IServiceCollection ConfigureAllQuartzSchedulers(this IServiceCollection services, Action<IQuartzBuilder> configure)
Parameters
servicesIServiceCollectionThe service collection to register into.
configureAction<IQuartzBuilder>Applied to every scheduler in the container.
Returns
Remarks
This is the options pattern's ConfigureAll, for schedulers. configure is
applied to every scheduler AddQuartz(), AddQuartz(name, …) or
AddQuartzSchedulers(…) registers in this container: the ones already registered when this
is called, and the ones registered after it. The order of the calls does not matter
— which is the point, since a package that adds something to every scheduler cannot know whether
the application registers its schedulers before or after calling it.
The delegate is given a builder per scheduler, so what it registers lands under that
scheduler's own service key, exactly as if it had been written inside that scheduler's
AddQuartz(name, q => …) callback. A plugin or listener added here is therefore one
instance per scheduler, each initialized with the name of the scheduler it belongs to — not one
instance shared between them, which would leave each scheduler but the last with a component
pointing at somebody else's.
It runs after each scheduler's own configuration callback, which is what makes the order of the two
calls immaterial: a scheduler registered later is configured then, and one registered earlier is
configured here, and both are after its own callback either way. One consequence is worth naming:
a middleware added here always composes inside one a scheduler's own AddQuartz
callback added, because middleware runs in registration order and this registration is always the
later of the two. That is the right way round — what a library wraps, an outbox or a unit of work,
belongs within what the application wraps, such as its tenant scope. The usual precedence follows —
registration is first-wins, so a component a scheduler chose for itself is not replaced by one
chosen here; options are last-wins, so a value set here overrides the same option set on one
scheduler, exactly as ConfigureAll<TOptions> overrides an earlier named
Configure.
Remote schedulers registered with AddQuartzHttpClient are not built by a builder and are
skipped. Calling this when no scheduler is registered at all is not an error: the delegate simply
applies to nothing.