NotableDateServiceCollectionExtensions Class
Definition
- Namespace
- Bodu.Globalization.Calendar
- Assembly
- Bodu.Globalization.Calendar.DependencyInjection.dll
- Package
- Bodu.Globalization.Calendar.DependencyInjection 1.0.0
Provides IServiceCollection extension methods for registering the Bodu notable-date service.
public static class NotableDateServiceCollectionExtensions
- Inheritance
-
NotableDateServiceCollectionExtensions
- Inherited Members
Bodu.Globalization.Calendar.DependencyInjection (package)
Purpose
The Bodu.Globalization.Calendar.DependencyInjection package provides the Microsoft.Extensions.DependencyInjection
integration for Bodu.Globalization.Calendar. It registers
INotableDateService as a singleton over a loaded
NotableDateResource (or a factory that produces one), so an ASP.NET Core application -
or any Microsoft.Extensions.*-style host - can inject the calendar service rather than composing
new NotableDateService(...) by hand.
The package is intentionally thin: a resource is an immutable, already-validated value, so registration takes the
resource (or a factory for it) directly, optionally with a NotableDateServiceOptions
carrying the service collaborators (algorithm registry, collision resolver, adjustment handlers, code-first providers).
There is no fluent builder - resource-level behavior is carried by the resource's <ResolutionPolicy>. Direct
construction continues to work for consoles, libraries, and tests that prefer not to bring in IServiceCollection.
There is no Bodu.Globalization.Calendar.DependencyInjection namespace: the package contributes exactly one public
type, this NotableDateServiceCollectionExtensions class, declared in the
Bodu.Globalization.Calendar namespace. Add using Bodu.Globalization.Calendar; to bring the extension methods into
scope on IServiceCollection.
Static documentation
- Introduction - the mental model, the full overload table, lifetimes and idempotency, headline types, and scenarios.
- Getting started - install, dependencies, and the plain, keyed, and reloadable samples with
appsettings.json, plus composing the caching decorator. - Calendar dependency injection guide - the complete walkthrough: factories, collaborators, the reloadable workflow, and lifetime semantics.
- Caching notable dates guide -
AddCachedNotableDateServiceand the durable backends that wrap these registrations.
The registration surface
All ten overloads are IServiceCollection extension methods on
NotableDateServiceCollectionExtensions; each returns the same collection for
chaining and throws ArgumentNullException for a null services, resource, factory, or key.
| Overload | Registers |
|---|---|
AddNotableDateService(IServiceCollection, NotableDateResource) |
A singleton INotableDateService over an already-loaded resource. |
AddNotableDateService(IServiceCollection, NotableDateResource, NotableDateServiceOptions?) |
The same, composed with the collaborators on NotableDateServiceOptions. |
AddNotableDateService(IServiceCollection, Func<IServiceProvider, NotableDateResource>) |
The resource is produced from the container when the service is first resolved - e.g. loaded from configuration or a data pack resolved through DI. |
AddNotableDateService(IServiceCollection, Func<IServiceProvider, NotableDateResource>, Func<IServiceProvider, NotableDateServiceOptions?>?) |
Factory registration with the collaborators also produced from the container; the options factory and its result may be null. |
AddNotableDateService(IServiceCollection, string serviceKey, NotableDateResource, NotableDateServiceOptions? = null) |
A keyed singleton, so a multi-tenant process registers one service per jurisdiction and resolves it with GetRequiredKeyedService<INotableDateService>(key) or [FromKeyedServices(key)]. |
AddNotableDateService(IServiceCollection, string serviceKey, Func<IServiceProvider, NotableDateResource>, Func<IServiceProvider, NotableDateServiceOptions?>? = null) |
The keyed registration with factory-produced resource and collaborators. |
AddReloadableNotableDateService(IServiceCollection, NotableDateResource) |
A singleton ReloadableNotableDateService together with a singleton MutableNotableDateResourceProvider (also exposed as INotableDateResourceProvider). Inject the mutable provider to call Reload(...); the live service picks up the new resource on its next query. |
AddReloadableNotableDateService(IServiceCollection, NotableDateResource, NotableDateServiceOptions?) |
The reloadable registration with collaborators propagated to each rebuilt inner service. |
AddReloadableNotableDateService(IServiceCollection, Func<IServiceProvider, NotableDateResource>, NotableDateServiceOptions? = null) |
The reloadable registration with the initial resource produced from the container. |
AddReloadableNotableDateService<TOptions>(IServiceCollection, Func<IServiceProvider, TOptions, NotableDateResource>, NotableDateServiceOptions? = null) where TOptions : class |
Driven by IOptionsMonitor<TOptions>: the factory runs for the initial load and again on every options change, and each rebuilt resource is swapped into the live service. A factory failure during a change is logged (EventId 4001) and leaves the previous resource in effect; a successful swap logs EventId 4002. |
INotableDateService is always a singleton, and every registration is idempotent (TryAdd semantics): a second
registration for the same service - or the same key - leaves the first in place. Keyed and unkeyed registrations are
independent, so both may coexist. Factories run lazily, on first resolution.
Minimal sample
using Bodu.Globalization.Calendar;
using Microsoft.Extensions.DependencyInjection;
// From a companion data pack (or NotableDateResourceLoader.Load(...) for your own document):
builder.Services.AddNotableDateService(AsiaPacificCalendarData.LoadResource("AU"));
// ... elsewhere, the resolved singleton is injected:
public sealed class HolidayController(INotableDateService calendar)
{
public IReadOnlyList<NotableDate> Year(int year) => calendar.Resolve(year, "AU-NSW");
}
Register one service per jurisdiction and resolve by key:
builder.Services.AddNotableDateService("US", AmericasCalendarData.LoadResource("US"));
builder.Services.AddNotableDateService("AU", AsiaPacificCalendarData.LoadResource("AU"));
public sealed class PayrollCalendar([FromKeyedServices("AU")] INotableDateService calendar);
To swap the rule set at run time, register the reloadable service and inject the mutable provider:
builder.Services.AddReloadableNotableDateService(EuropeCalendarData.LoadResource("GB"));
// later, when the rules change:
provider.Reload(NotableDateResourceLoader.Load(updatedXml, CommonNotableDateResources.Resolver));
Or let configuration drive the reloads through a bound options class:
builder.Services.AddOptions<CalendarOptions>().Bind(builder.Configuration.GetSection("Calendar"));
builder.Services.AddReloadableNotableDateService<CalendarOptions>((sp, options) =>
AsiaPacificCalendarData.LoadResource(options.Territory));
The Bodu.Globalization.Calendar.Caching decorator composes with any of
these: services.AddCachedNotableDateService(...), called after the registration it wraps, replaces the registered
INotableDateService with a caching decorator over it and observes the reloadable provider automatically. See the
Calendar dependency injection guide for the full walkthrough, including
the reloadable workflow and lifetime semantics.
Examples
// Register a service over a bundled data pack at application startup.
builder.Services.AddNotableDateService(AmericasCalendarData.LoadResource("US"));
// Or register one service per jurisdiction and resolve by key.
builder.Services.AddNotableDateService("US", AmericasCalendarData.LoadResource("US"));
builder.Services.AddNotableDateService("AU", AsiaPacificCalendarData.LoadResource("AU"));
public sealed class PayrollCalendar([FromKeyedServices("US")] INotableDateService notableDates)
{
public bool IsBankHoliday(DateOnly date) =>
notableDates.Resolve(date, "US").Any(n => n.Category == NotableDateCategory.BankHoliday);
}
Remarks
The service is registered as a singleton because a NotableDateResource is immutable and the resolver
holds no shared mutable state, so a single instance can be shared across the application safely. Registrations are
idempotent (TryAdd semantics): when an INotableDateService - or, for the keyed overloads, a
service under the same key - is already registered, the call leaves the existing registration in place.
When to use. Use AddNotableDateService(IServiceCollection, NotableDateResource) when the resource is available at startup, the factory overloads when it must be built from other registered services, the overloads accepting a NotableDateServiceOptions when the service needs collaborators (a custom algorithm registry, collision resolver, adjustment handlers, or code-first providers), the keyed overloads when a multi-tenant process serves several jurisdictions side by side, and AddReloadableNotableDateService(IServiceCollection, NotableDateResource) when the data must be swapped at runtime without restarting the host.
Methods
AddNotableDateService(IServiceCollection, NotableDateResource)
Registers an INotableDateService resolving against the supplied resource.
public static IServiceCollection AddNotableDateService(this IServiceCollection services, NotableDateResource resource)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
resourceNotableDateResourceThe loaded resource the service resolves against.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Exceptions
- ArgumentNullException
servicesorresourceis null.
AddNotableDateService(IServiceCollection, NotableDateResource, NotableDateServiceOptions?)
Registers an INotableDateService resolving against the supplied resource with the supplied collaborators.
public static IServiceCollection AddNotableDateService(this IServiceCollection services, NotableDateResource resource, NotableDateServiceOptions? options)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
resourceNotableDateResourceThe loaded resource the service resolves against.
optionsNotableDateServiceOptionsThe collaborators composed into the service - for example a custom algorithm registry - or null for built-ins only.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Exceptions
- ArgumentNullException
servicesorresourceis null.
AddNotableDateService(IServiceCollection, Func<IServiceProvider, NotableDateResource>)
Registers an INotableDateService resolving against a resource produced by a factory.
public static IServiceCollection AddNotableDateService(this IServiceCollection services, Func<IServiceProvider, NotableDateResource> resourceFactory)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
resourceFactoryFunc<IServiceProvider, NotableDateResource>A factory that produces the resource from the service provider.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Exceptions
- ArgumentNullException
servicesorresourceFactoryis null.
AddNotableDateService(IServiceCollection, Func<IServiceProvider, NotableDateResource>, Func<IServiceProvider, NotableDateServiceOptions?>?)
Registers an INotableDateService resolving against a resource produced by a factory, composed with collaborators produced by a second factory.
public static IServiceCollection AddNotableDateService(this IServiceCollection services, Func<IServiceProvider, NotableDateResource> resourceFactory, Func<IServiceProvider, NotableDateServiceOptions?>? optionsFactory)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
resourceFactoryFunc<IServiceProvider, NotableDateResource>A factory that produces the resource from the service provider.
optionsFactoryFunc<IServiceProvider, NotableDateServiceOptions>A factory that produces the collaborators composed into the service, or null for built-ins only. The factory itself may also return null.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Exceptions
- ArgumentNullException
servicesorresourceFactoryis null.
AddNotableDateService(IServiceCollection, string, NotableDateResource, NotableDateServiceOptions?)
Registers a keyed INotableDateService resolving against the supplied resource, so a multi-tenant process can register one service per jurisdiction and resolve them by key.
public static IServiceCollection AddNotableDateService(this IServiceCollection services, string serviceKey, NotableDateResource resource, NotableDateServiceOptions? options = null)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
serviceKeystringThe key the service is registered and resolved under.
resourceNotableDateResourceThe loaded resource the service resolves against.
optionsNotableDateServiceOptionsThe collaborators composed into the service, or null for built-ins only.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Remarks
Consumers resolve the keyed service with GetRequiredKeyedService<INotableDateService>(serviceKey)
or a [FromKeyedServices(serviceKey)] constructor parameter. Keyed registrations are independent of the
unkeyed registration - registering both is supported.
Exceptions
- ArgumentNullException
services,serviceKey, orresourceis null.
AddNotableDateService(IServiceCollection, string, Func<IServiceProvider, NotableDateResource>, Func<IServiceProvider, NotableDateServiceOptions?>?)
Registers a keyed INotableDateService resolving against a resource produced by a factory.
public static IServiceCollection AddNotableDateService(this IServiceCollection services, string serviceKey, Func<IServiceProvider, NotableDateResource> resourceFactory, Func<IServiceProvider, NotableDateServiceOptions?>? optionsFactory = null)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
serviceKeystringThe key the service is registered and resolved under.
resourceFactoryFunc<IServiceProvider, NotableDateResource>A factory that produces the resource from the service provider.
optionsFactoryFunc<IServiceProvider, NotableDateServiceOptions>A factory that produces the collaborators composed into the service, or null for built-ins only. The factory itself may also return null.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Exceptions
- ArgumentNullException
services,serviceKey, orresourceFactoryis null.
AddReloadableNotableDateService(IServiceCollection, NotableDateResource)
Registers a reloadable INotableDateService over a MutableNotableDateResourceProvider so the resolved data can be swapped at runtime.
public static IServiceCollection AddReloadableNotableDateService(this IServiceCollection services, NotableDateResource initialResource)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
initialResourceNotableDateResourceThe resource the service resolves against until it is reloaded.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Remarks
The provider is registered as a singleton under both MutableNotableDateResourceProvider and INotableDateResourceProvider; injecting the former lets a caller reload the resource, after which the resolved INotableDateService reflects the new data on its next query.
// Register a reloadable service with an initial resource.
builder.Services.AddReloadableNotableDateService(AmericasCalendarData.LoadResource("US"));
// Later, swap in fresh data without restarting the host. Subsequent queries see the new resource.
MutableNotableDateResourceProvider provider =
app.Services.GetRequiredService<MutableNotableDateResourceProvider>();
provider.Reload(AmericasCalendarData.LoadResource("CA"));
Exceptions
- ArgumentNullException
servicesorinitialResourceis null.
AddReloadableNotableDateService(IServiceCollection, NotableDateResource, NotableDateServiceOptions?)
Registers a reloadable INotableDateService with the supplied collaborators propagated to each rebuilt inner service.
public static IServiceCollection AddReloadableNotableDateService(this IServiceCollection services, NotableDateResource initialResource, NotableDateServiceOptions? options)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
initialResourceNotableDateResourceThe resource the service resolves against until it is reloaded.
optionsNotableDateServiceOptionsThe collaborators propagated to each rebuilt inner service, or null for built-ins only.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Exceptions
- ArgumentNullException
servicesorinitialResourceis null.
AddReloadableNotableDateService(IServiceCollection, Func<IServiceProvider, NotableDateResource>, NotableDateServiceOptions?)
Registers a reloadable INotableDateService whose initial resource is produced by a factory.
public static IServiceCollection AddReloadableNotableDateService(this IServiceCollection services, Func<IServiceProvider, NotableDateResource> initialResourceFactory, NotableDateServiceOptions? options = null)
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
initialResourceFactoryFunc<IServiceProvider, NotableDateResource>A factory that produces the initial resource from the service provider.
optionsNotableDateServiceOptionsThe collaborators propagated to each rebuilt inner service, or null for built-ins only.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Exceptions
- ArgumentNullException
servicesorinitialResourceFactoryis null.
AddReloadableNotableDateService<TOptions>(IServiceCollection, Func<IServiceProvider, TOptions, NotableDateResource>, NotableDateServiceOptions?)
Registers a reloadable INotableDateService whose resource is rebuilt automatically whenever the monitored options change.
public static IServiceCollection AddReloadableNotableDateService<TOptions>(this IServiceCollection services, Func<IServiceProvider, TOptions, NotableDateResource> resourceFactory, NotableDateServiceOptions? options = null) where TOptions : class
Parameters
servicesIServiceCollectionThe service collection to add the registration to.
resourceFactoryFunc<IServiceProvider, TOptions, NotableDateResource>The factory producing the resource from the current options; invoked once for the initial load and again on every options change.
optionsNotableDateServiceOptionsThe collaborators propagated to each rebuilt inner service, or null for built-ins only.
Returns
- IServiceCollection
The same service collection, to allow chaining.
Type Parameters
TOptionsThe options type driving the resource; monitored via IOptionsMonitor<TOptions>.
Examples
builder.Services.AddOptions<CalendarOptions>().Bind(builder.Configuration.GetSection("Calendar"));
builder.Services.AddReloadableNotableDateService<CalendarOptions>((sp, options) =>
AsiaPacificCalendarData.LoadResource(options.Territory));
Remarks
The registration binds the reloadable service to the options infrastructure: configure
TOptions through the standard AddOptions<TOptions>() surface (for example
bound to a configuration section), and every change notification rebuilds the resource through
resourceFactory and swaps it into the live service. A factory failure during a change is
logged and leaves the previously loaded resource in effect - a broken configuration edit never faults the reload
thread or takes the calendar offline.
Exceptions
- ArgumentNullException
servicesorresourceFactoryis null.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |