Table of Contents

Class QuartzBuilderExtensions

Namespace
Quartz
Assembly
Quartz.dll

Adds jobs, triggers and calendars to a scheduler, and selects the built-in type loader.

public static class QuartzBuilderExtensions
Inheritance
QuartzBuilderExtensions
Inherited Members

Remarks

These extend IQuartzBuilder, so they read the same whether the scheduler is being registered with AddQuartz or built by QuartzSchedulerBuilder. They are extension methods rather than interface members because each is a composition of what the interface already offers, and an implementation of it should not have to reproduce them.

Methods

AddCalendar(IQuartzBuilder, string, ICalendar, AddCalendarOptions)

Adds a calendar the caller has already built.

public static IQuartzBuilder AddCalendar(this IQuartzBuilder builder, string name, ICalendar calendar, AddCalendarOptions options = default)

Parameters

builder IQuartzBuilder

The builder.

name string

The name triggers refer to the calendar by.

calendar ICalendar

The calendar.

options AddCalendarOptions

How the calendar is added: whether it replaces one of the same name, and whether triggers using that name are recomputed. Defaults to replacing nothing.

Returns

IQuartzBuilder

AddCalendar(IQuartzBuilder, string, Func<IServiceProvider, ICalendar>, AddCalendarOptions)

Adds a calendar built from the container.

public static IQuartzBuilder AddCalendar(this IQuartzBuilder builder, string name, Func<IServiceProvider, ICalendar> factory, AddCalendarOptions options = default)

Parameters

builder IQuartzBuilder

The builder.

name string

The name triggers refer to the calendar by.

factory Func<IServiceProvider, ICalendar>

Builds the calendar from the container.

options AddCalendarOptions

How the calendar is added: whether it replaces one of the same name, and whether triggers using that name are recomputed. Defaults to replacing nothing.

Returns

IQuartzBuilder

Remarks

The generic forms above create the calendar with new T(), so a calendar that needs a dependency — a holiday list read from a database, a clock, an options snapshot — cannot use them. This one hands the factory the scheduler-scoped IServiceProvider, so a calendar registered for a named scheduler is given that scheduler's parts. The factory runs once, when the scheduler's content is resolved.

AddCalendar<T>(IQuartzBuilder, string, AddCalendarOptions, Action<IServiceProvider, T>)

Adds a calendar the scheduler should carry, which triggers exclude days with.

public static IQuartzBuilder AddCalendar<T>(this IQuartzBuilder builder, string name, AddCalendarOptions options, Action<IServiceProvider, T> configure) where T : ICalendar, new()

Parameters

builder IQuartzBuilder

The builder.

name string

The name triggers refer to the calendar by.

options AddCalendarOptions

How the calendar is added: whether it replaces one of the same name, and whether triggers using that name are recomputed. Defaults to replacing nothing.

configure Action<IServiceProvider, T>

Configures the calendar, which is created with its default constructor.

Returns

IQuartzBuilder

Type Parameters

T

The calendar's type.

AddCalendar<T>(IQuartzBuilder, string, AddCalendarOptions, Action<T>?)

Adds a calendar the scheduler should carry, which triggers exclude days with.

public static IQuartzBuilder AddCalendar<T>(this IQuartzBuilder builder, string name, AddCalendarOptions options = default, Action<T>? configure = null) where T : ICalendar, new()

Parameters

builder IQuartzBuilder

The builder.

name string

The name triggers refer to the calendar by.

options AddCalendarOptions

How the calendar is added: whether it replaces one of the same name, and whether triggers using that name are recomputed. Defaults to replacing nothing.

configure Action<T>

Configures the calendar, which is created with its default constructor.

Returns

IQuartzBuilder

Type Parameters

T

The calendar's type.

AddJob(IQuartzBuilder, Type, Action<IJobConfigurator<IJob>>)

Adds a job of a type only known at runtime.

public static IQuartzBuilder AddJob(this IQuartzBuilder builder, Type jobType, Action<IJobConfigurator<IJob>> configure)

Parameters

builder IQuartzBuilder

The builder.

jobType Type

The job's type, which must implement IJob.

configure Action<IJobConfigurator<IJob>>

Configures the job. Its identity is set here with WithIdentity; a job given none gets a generated one, which a persistent store cannot recognise again on the next start.

Returns

IQuartzBuilder

Remarks

Registers the job type with the container, so a dependency it cannot be given is reported when the container is validated rather than when the trigger fires.

The registration is scoped, matching the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns. A singleton would serve every fire from one instance and capture the scoped dependencies handed to the first one; a transient would leave two resolutions inside one fire — the job and something it injects — disagreeing about which unit of work they are in.

It is a TryAdd, so a registration the application made itself — with its own lifetime, factory or implementation type — is kept, and adding the same job twice is harmless.

Being registered is also what makes the job the container's to build rather than the job factory's to activate, so the scheduler is recorded as having been given it and Quartz.Configuration.RegisteredJobConstructorValidator checks at startup that its constructor asks for nothing that belongs to one scheduler.

AddJob(IQuartzBuilder, Type, Action<IServiceProvider, IJobConfigurator<IJob>>)

Adds a job of a type only known at runtime.

public static IQuartzBuilder AddJob(this IQuartzBuilder builder, Type jobType, Action<IServiceProvider, IJobConfigurator<IJob>> configure)

Parameters

builder IQuartzBuilder

The builder.

jobType Type

The job's type, which must implement IJob.

configure Action<IServiceProvider, IJobConfigurator<IJob>>

Configures the job. Its identity is set here with WithIdentity; a job given none gets a generated one, which a persistent store cannot recognise again on the next start.

Returns

IQuartzBuilder

Remarks

Registers the job type with the container, so a dependency it cannot be given is reported when the container is validated rather than when the trigger fires.

The registration is scoped, matching the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns. A singleton would serve every fire from one instance and capture the scoped dependencies handed to the first one; a transient would leave two resolutions inside one fire — the job and something it injects — disagreeing about which unit of work they are in.

It is a TryAdd, so a registration the application made itself — with its own lifetime, factory or implementation type — is kept, and adding the same job twice is harmless.

Being registered is also what makes the job the container's to build rather than the job factory's to activate, so the scheduler is recorded as having been given it and Quartz.Configuration.RegisteredJobConstructorValidator checks at startup that its constructor asks for nothing that belongs to one scheduler.

AddJobTimeout(IQuartzBuilder, TimeSpan?)

Bounds how long a firing may run: when its budget is spent the execution is interrupted, and the overrun is reported as the job's own failure.

public static IQuartzBuilder AddJobTimeout(this IQuartzBuilder builder, TimeSpan? defaultTimeout = null)

Parameters

builder IQuartzBuilder

The builder.

defaultTimeout TimeSpan?

How long a job that carries no JobTimeoutAttribute may run. null, the default, bounds only the jobs that declare a budget of their own.

Returns

IQuartzBuilder

Remarks

A middleware, registered where the call is written, so it takes its place in the chain like any other — outside a log scope registered after it, inside one registered before. It is an extension rather than a member of IQuartzBuilder for the reason everything else here is: it is AddJobMiddleware with the built-in middleware, and an implementation of the interface should not have to reproduce it.

How the budget is found. The job type's JobTimeoutAttribute decides, and defaultTimeout applies to every job that carries none. A job declaring [JobTimeout("00:00:00")] has no timeout at all, so a long-running job is exempt from a scheduler-wide default rather than fighting it. Called with no argument, only the jobs that declare a budget are bounded.

What a timeout does. The firing is interrupted through InterruptFireInstance(string, CancellationToken), exactly as an operator's interrupt would, so the job's CancellationToken — the one it was handed — is cancelled and JobInterrupted(IScheduler, JobKey, string, CancellationToken) is raised. The middleware then raises a JobExecutionException naming the budget, which is what makes a timeout a failure: without it an interrupt looks like a completed job, and the trigger's RetryPolicy would never be consulted. With it, a timed-out firing is retried like any other failure, and each attempt gets the whole budget again.

A job that ignores its token cannot be stopped. Cancellation is cooperative; nothing here aborts a thread. A job that never looks at its token runs to completion and is reported as timed out when it finally returns — which is worth knowing before a budget is relied on to free a thread-pool slot. CA2016 is what polices forwarding the token.

Exceptions

ArgumentOutOfRangeException

defaultTimeout is zero or negative. A scheduler-wide default of nothing is what leaving it out already says.

AddJobType<TJob>(IQuartzBuilder)

Registers how this scheduler builds a job type, so two schedulers in one container can build the same job type differently.

public static IQuartzBuilder AddJobType<TJob>(this IQuartzBuilder builder) where TJob : class, IJob

Parameters

builder IQuartzBuilder

The builder.

Returns

IQuartzBuilder

Type Parameters

TJob

The job type, as named on the job detail.

Remarks

AddJob<T>(IQuartzBuilder, Action<IJobConfigurator<T>>) registers the job type with the container unkeyed, which is what a single-scheduler application wants and what container validation reads. Under a scheduler per tenant that one registration is shared: whichever implementation or lifetime was registered first is what every scheduler gets. This says the registration belongs to one scheduler, and the job factory looks there first.

The registration is made under this scheduler's service key, or unkeyed for the default scheduler — whose registrations are the unkeyed ones, so an empty key would not be the same thing. It replaces rather than defers to what AddJob registered: naming the implementation is the whole point of the call.

A job is built with Scoped unless another lifetime is named, which matches the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns.

The lifetime is an overload rather than an optional parameter deliberately. A default value that is an enum from an assembly which only exists in a shared framework — ServiceLifetime is one — is a metadata constant whose type Cecil has to resolve to write it, and coverlet's resolver cannot: it fails to instrument the whole assembly and reports Quartz as untested, silently. One optional parameter cost the core assembly its entire coverage figure; overloads carry no constant.

AddJobType<TJob>(IQuartzBuilder, ServiceLifetime)

Registers how this scheduler builds a job type, so two schedulers in one container can build the same job type differently.

public static IQuartzBuilder AddJobType<TJob>(this IQuartzBuilder builder, ServiceLifetime lifetime) where TJob : class, IJob

Parameters

builder IQuartzBuilder

The builder.

lifetime ServiceLifetime

How long one instance lives.

Returns

IQuartzBuilder

Type Parameters

TJob

AddJobType<TJob>(IQuartzBuilder, Func<IServiceProvider, TJob>)

Registers how this scheduler constructs a job type, with a factory of your own.

public static IQuartzBuilder AddJobType<TJob>(this IQuartzBuilder builder, Func<IServiceProvider, TJob> implementationFactory) where TJob : class, IJob

Parameters

builder IQuartzBuilder

The builder.

implementationFactory Func<IServiceProvider, TJob>

Builds the job.

Returns

IQuartzBuilder

Type Parameters

TJob

The job type, as named on the job detail.

Remarks

AddJob<T>(IQuartzBuilder, Action<IJobConfigurator<T>>) registers the job type with the container unkeyed, which is what a single-scheduler application wants and what container validation reads. Under a scheduler per tenant that one registration is shared: whichever implementation or lifetime was registered first is what every scheduler gets. This says the registration belongs to one scheduler, and the job factory looks there first.

The registration is made under this scheduler's service key, or unkeyed for the default scheduler — whose registrations are the unkeyed ones, so an empty key would not be the same thing. It replaces rather than defers to what AddJob registered: naming the implementation is the whole point of the call.

A job is built with Scoped unless another lifetime is named, which matches the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns.

The lifetime is an overload rather than an optional parameter deliberately. A default value that is an enum from an assembly which only exists in a shared framework — ServiceLifetime is one — is a metadata constant whose type Cecil has to resolve to write it, and coverlet's resolver cannot: it fails to instrument the whole assembly and reports Quartz as untested, silently. One optional parameter cost the core assembly its entire coverage figure; overloads carry no constant.

AddJobType<TJob>(IQuartzBuilder, Func<IServiceProvider, TJob>, ServiceLifetime)

Registers how this scheduler constructs a job type, with a factory of your own.

public static IQuartzBuilder AddJobType<TJob>(this IQuartzBuilder builder, Func<IServiceProvider, TJob> implementationFactory, ServiceLifetime lifetime) where TJob : class, IJob

Parameters

builder IQuartzBuilder

The builder.

implementationFactory Func<IServiceProvider, TJob>

Builds the job.

lifetime ServiceLifetime

How long one instance lives.

Returns

IQuartzBuilder

Type Parameters

TJob

AddJobType<TJob, TImplementation>(IQuartzBuilder)

Registers the implementation this scheduler builds a job type with.

public static IQuartzBuilder AddJobType<TJob, TImplementation>(this IQuartzBuilder builder) where TJob : class, IJob where TImplementation : class, TJob

Parameters

builder IQuartzBuilder

The builder.

Returns

IQuartzBuilder

Type Parameters

TJob

The job type, as named on the job detail.

TImplementation

The type actually constructed.

Remarks

AddJob<T>(IQuartzBuilder, Action<IJobConfigurator<T>>) registers the job type with the container unkeyed, which is what a single-scheduler application wants and what container validation reads. Under a scheduler per tenant that one registration is shared: whichever implementation or lifetime was registered first is what every scheduler gets. This says the registration belongs to one scheduler, and the job factory looks there first.

The registration is made under this scheduler's service key, or unkeyed for the default scheduler — whose registrations are the unkeyed ones, so an empty key would not be the same thing. It replaces rather than defers to what AddJob registered: naming the implementation is the whole point of the call.

A job is built with Scoped unless another lifetime is named, which matches the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns.

The lifetime is an overload rather than an optional parameter deliberately. A default value that is an enum from an assembly which only exists in a shared framework — ServiceLifetime is one — is a metadata constant whose type Cecil has to resolve to write it, and coverlet's resolver cannot: it fails to instrument the whole assembly and reports Quartz as untested, silently. One optional parameter cost the core assembly its entire coverage figure; overloads carry no constant.

AddJobType<TJob, TImplementation>(IQuartzBuilder, ServiceLifetime)

Registers the implementation this scheduler builds a job type with.

public static IQuartzBuilder AddJobType<TJob, TImplementation>(this IQuartzBuilder builder, ServiceLifetime lifetime) where TJob : class, IJob where TImplementation : class, TJob

Parameters

builder IQuartzBuilder

The builder.

lifetime ServiceLifetime

How long one instance lives.

Returns

IQuartzBuilder

Type Parameters

TJob
TImplementation

AddJob<T>(IQuartzBuilder, Action<IJobConfigurator<T>>)

Adds a job the scheduler should carry.

public static IQuartzBuilder AddJob<T>(this IQuartzBuilder builder, Action<IJobConfigurator<T>> configure) where T : IJob

Parameters

builder IQuartzBuilder

The builder.

configure Action<IJobConfigurator<T>>

Configures the job. Its identity is set here with WithIdentity; a job given none gets a generated one, which a persistent store cannot recognise again on the next start.

Returns

IQuartzBuilder

Type Parameters

T

The job's type.

Remarks

Registers the job type with the container, so a dependency it cannot be given is reported when the container is validated rather than when the trigger fires.

The registration is scoped, matching the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns. A singleton would serve every fire from one instance and capture the scoped dependencies handed to the first one; a transient would leave two resolutions inside one fire — the job and something it injects — disagreeing about which unit of work they are in.

It is a TryAdd, so a registration the application made itself — with its own lifetime, factory or implementation type — is kept, and adding the same job twice is harmless.

Being registered is also what makes the job the container's to build rather than the job factory's to activate, so the scheduler is recorded as having been given it and Quartz.Configuration.RegisteredJobConstructorValidator checks at startup that its constructor asks for nothing that belongs to one scheduler.

AddJob<T>(IQuartzBuilder, Action<IServiceProvider, IJobConfigurator<T>>)

Adds a job the scheduler should carry.

public static IQuartzBuilder AddJob<T>(this IQuartzBuilder builder, Action<IServiceProvider, IJobConfigurator<T>> configure) where T : IJob

Parameters

builder IQuartzBuilder

The builder.

configure Action<IServiceProvider, IJobConfigurator<T>>

Configures the job. Its identity is set here with WithIdentity; a job given none gets a generated one, which a persistent store cannot recognise again on the next start.

Returns

IQuartzBuilder

Type Parameters

T

The job's type.

Remarks

Registers the job type with the container, so a dependency it cannot be given is reported when the container is validated rather than when the trigger fires.

The registration is scoped, matching the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns. A singleton would serve every fire from one instance and capture the scoped dependencies handed to the first one; a transient would leave two resolutions inside one fire — the job and something it injects — disagreeing about which unit of work they are in.

It is a TryAdd, so a registration the application made itself — with its own lifetime, factory or implementation type — is kept, and adding the same job twice is harmless.

Being registered is also what makes the job the container's to build rather than the job factory's to activate, so the scheduler is recorded as having been given it and Quartz.Configuration.RegisteredJobConstructorValidator checks at startup that its constructor asks for nothing that belongs to one scheduler.

AddTrigger(IQuartzBuilder, Action<ITriggerConfigurator<IJob>>)

Adds a trigger for a job added elsewhere, named by key.

public static IQuartzBuilder AddTrigger(this IQuartzBuilder builder, Action<ITriggerConfigurator<IJob>> configure)

Parameters

builder IQuartzBuilder

The builder.

configure Action<ITriggerConfigurator<IJob>>

Configures the trigger, which must name its job with ForJob.

Returns

IQuartzBuilder

Remarks

The job type on AddTrigger<TJob>(IQuartzBuilder, Action<ITriggerConfigurator<TJob>>) is what lets a trigger's job data name the job's properties; a trigger that only points at a job with ForJob has no use for it, and this is that call without the <IJob>.

AddTrigger(IQuartzBuilder, Action<IServiceProvider, ITriggerConfigurator<IJob>>)

Adds a trigger for a job added elsewhere, named by key.

public static IQuartzBuilder AddTrigger(this IQuartzBuilder builder, Action<IServiceProvider, ITriggerConfigurator<IJob>> configure)

Parameters

builder IQuartzBuilder

The builder.

configure Action<IServiceProvider, ITriggerConfigurator<IJob>>

Configures the trigger, which must name its job with ForJob.

Returns

IQuartzBuilder

Remarks

The job type on AddTrigger<TJob>(IQuartzBuilder, Action<ITriggerConfigurator<TJob>>) is what lets a trigger's job data name the job's properties; a trigger that only points at a job with ForJob has no use for it, and this is that call without the <IJob>.

AddTrigger<TJob>(IQuartzBuilder, Action<ITriggerConfigurator<TJob>>)

Adds a trigger for a job of a known type.

public static IQuartzBuilder AddTrigger<TJob>(this IQuartzBuilder builder, Action<ITriggerConfigurator<TJob>> configure) where TJob : IJob

Parameters

builder IQuartzBuilder

The builder.

configure Action<ITriggerConfigurator<TJob>>

Configures the trigger.

Returns

IQuartzBuilder

Type Parameters

TJob

The type of job the trigger fires.

Remarks

Naming the job type is what lets the trigger's job data name the job's properties. The trigger still has to be pointed at a job with ForJob, and since that is done by key here, nothing checks that the key resolves to a TJob - the type names the properties, it does not pick the job. Use AddTrigger<IJob> for a trigger whose job data names nothing.

AddTrigger<TJob>(IQuartzBuilder, Action<IServiceProvider, ITriggerConfigurator<TJob>>)

Adds a trigger for a job of a known type.

public static IQuartzBuilder AddTrigger<TJob>(this IQuartzBuilder builder, Action<IServiceProvider, ITriggerConfigurator<TJob>> configure) where TJob : IJob

Parameters

builder IQuartzBuilder

The builder.

configure Action<IServiceProvider, ITriggerConfigurator<TJob>>

Configures the trigger.

Returns

IQuartzBuilder

Type Parameters

TJob

The type of job the trigger fires.

Remarks

Naming the job type is what lets the trigger's job data name the job's properties. The trigger still has to be pointed at a job with ForJob, and since that is done by key here, nothing checks that the key resolves to a TJob - the type names the properties, it does not pick the job. Use AddTrigger<IJob> for a trigger whose job data names nothing.

ConfigureJobScope(IQuartzBuilder, Action<IServiceScope, TriggerFiredBundle, IScheduler>)

Prepares the dependency injection scope each job is built in, so services that are scoped can be given the ambient context of the job about to run.

public static IQuartzBuilder ConfigureJobScope(this IQuartzBuilder builder, Action<IServiceScope, TriggerFiredBundle, IScheduler> configure)

Parameters

builder IQuartzBuilder

The builder.

configure Action<IServiceScope, TriggerFiredBundle, IScheduler>

Prepares the scope, given the scope, the fire it was opened for and the scheduler firing it.

Returns

IQuartzBuilder

Remarks

The callback runs before the job is resolved, so anything it sets is in place while the job and everything it injects are constructed. It is synchronous by design: an asynchronous hook would be awaited, and the ExecutionContext restored on the way back would discard exactly the AsyncLocal<T> values it exists to set.

Callbacks combine rather than replace, and run in the order they were added. This was previously reachable only by deriving from MicrosoftDependencyInjectionJobFactory and overriding a protected method, which is a great deal of ceremony for setting one ambient value.

TriggerFiredBundle comes from Quartz.Extensibility, which is the one place on this builder where a mainstream caller meets that namespace without supplying a component. It is ratified rather than papered over: the callback runs before the job exists, and IJobExecutionContext — the type this would otherwise hand over — is constructed around a job instance. The bundle is what a firing is before there is a job to put in a context, so a mainstream stand-in would be a second bundle carrying the same four values.

ScheduleJob<T>(IQuartzBuilder, Action<ITriggerConfigurator<T>>, Action<IJobConfigurator<T>>?)

Adds a job together with the one trigger that fires it.

public static IQuartzBuilder ScheduleJob<T>(this IQuartzBuilder builder, Action<ITriggerConfigurator<T>> trigger, Action<IJobConfigurator<T>>? job = null) where T : IJob

Parameters

builder IQuartzBuilder

The builder.

trigger Action<ITriggerConfigurator<T>>

Configures the trigger.

job Action<IJobConfigurator<T>>

Configures the job, which most schedules do not need to.

Returns

IQuartzBuilder

Type Parameters

T

The job's type.

Remarks

The job takes the trigger's identity unless it is given one of its own, so a job and its only trigger can be referred to by a single name.

Registers the job type with the container, so a dependency it cannot be given is reported when the container is validated rather than when the trigger fires.

The registration is scoped, matching the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns. A singleton would serve every fire from one instance and capture the scoped dependencies handed to the first one; a transient would leave two resolutions inside one fire — the job and something it injects — disagreeing about which unit of work they are in.

It is a TryAdd, so a registration the application made itself — with its own lifetime, factory or implementation type — is kept, and adding the same job twice is harmless.

Being registered is also what makes the job the container's to build rather than the job factory's to activate, so the scheduler is recorded as having been given it and Quartz.Configuration.RegisteredJobConstructorValidator checks at startup that its constructor asks for nothing that belongs to one scheduler.

ScheduleJob<T>(IQuartzBuilder, Action<IServiceProvider, ITriggerConfigurator<T>>, Action<IServiceProvider, IJobConfigurator<T>>?)

Adds a job together with the one trigger that fires it.

public static IQuartzBuilder ScheduleJob<T>(this IQuartzBuilder builder, Action<IServiceProvider, ITriggerConfigurator<T>> trigger, Action<IServiceProvider, IJobConfigurator<T>>? job = null) where T : IJob

Parameters

builder IQuartzBuilder

The builder.

trigger Action<IServiceProvider, ITriggerConfigurator<T>>

Configures the trigger.

job Action<IServiceProvider, IJobConfigurator<T>>

Configures the job, which most schedules do not need to.

Returns

IQuartzBuilder

Type Parameters

T

The job's type.

Remarks

The job takes the trigger's identity unless it is given one of its own, so a job and its only trigger can be referred to by a single name.

Registers the job type with the container, so a dependency it cannot be given is reported when the container is validated rather than when the trigger fires.

The registration is scoped, matching the lifetime the job factory resolves with: a scope is opened per fire, the job is resolved from it, and the scope is disposed once the job returns. A singleton would serve every fire from one instance and capture the scoped dependencies handed to the first one; a transient would leave two resolutions inside one fire — the job and something it injects — disagreeing about which unit of work they are in.

It is a TryAdd, so a registration the application made itself — with its own lifetime, factory or implementation type — is kept, and adding the same job twice is harmless.

Being registered is also what makes the job the container's to build rather than the job factory's to activate, so the scheduler is recorded as having been given it and Quartz.Configuration.RegisteredJobConstructorValidator checks at startup that its constructor asks for nothing that belongs to one scheduler.

UseSimpleTypeLoader(IQuartzBuilder)

Uses the default type loader, which resolves type names against loaded assemblies.

public static IQuartzBuilder UseSimpleTypeLoader(this IQuartzBuilder builder)

Parameters

builder IQuartzBuilder

Returns

IQuartzBuilder

Remarks

This is the public way to ask for the built-in loader: SimpleTypeLoader is internal, because a type-loading strategy is not something to derive from, so there is no UseTypeLoader<SimpleTypeLoader>() to write instead. It is also already the default, so calling it only matters where something else registered a loader first.

UseTypeLoader(IQuartzBuilder, Action<TypeLoaderOptions>)

Configures the type loader, which is where a job type that was renamed says what it is called now.

public static IQuartzBuilder UseTypeLoader(this IQuartzBuilder builder, Action<TypeLoaderOptions> configure)

Parameters

builder IQuartzBuilder

The builder.

configure Action<TypeLoaderOptions>

Declares the renames.

Returns

IQuartzBuilder

Remarks

UseTypeLoader<T>() replaces the loader; this configures the one Quartz ships. Declaring a rename here is the declarative form of the rename-aware loader the troubleshooting page used to be the only answer — one line per renamed type instead of a class to write, register and keep — and the same map can arrive from configuration under Quartz:TypeLoader:Aliases, so a rename can ship with the deployment that performs it.

The options are the container's rather than one scheduler's, because the loader is: a rename declared through any scheduler's builder is in force for every scheduler in the container. An alias whose target names no loadable type fails validation at startup.