Common Options Builders¶
Use a lightweight fluent builder convention for feature-specific configuration objects.
Common.Options provides the lightweight builder pattern that many devkit packages use for configuration objects. It is not a replacement for Microsoft.Extensions.Options; it is a small, reusable convention for constructing feature-specific options with fluent APIs.
This explains why many devkit packages expose configuration like:
builder.Services.AddSomething(o => o
.WithX(...)
.WithY(...));
Why This Pattern Exists¶
The devkit uses builder-based options when a package needs:
- a fluent configuration API
- simple construction without a large framework dependency
- optional logging support on the options object itself
- reusable configuration code across runtime and tests
This pattern keeps package configuration small and explicit while still being pleasant to use.
Core Types¶
IOptionsBuilder and IOptionsBuilder<T>¶
These interfaces define the minimal contract for builders that construct option objects. They expose the underlying target object and a Build() method.
OptionsBuilder<T>¶
OptionsBuilder<T> is the simplest reusable builder. It:
- creates a new
T - exposes it through
Target - returns it from
Build()
Use this when your options type does not need special logging or additional fluent base methods.
OptionsBase¶
OptionsBase is the common base class for option types that want logger creation support. It carries an optional ILoggerFactory and exposes:
CreateLogger(string categoryName)CreateLogger<T>()
This is useful for infrastructure options that need to create internal loggers without forcing every caller to wire that manually.
OptionsBuilderBase<TOption, TBuilder>¶
This is the typed fluent base class for builders whose option type derives from OptionsBase.
Its main shared feature is:
LoggerFactory(ILoggerFactory loggerFactory)
Builders in other packages often inherit from this class so they automatically support fluent logger configuration plus package-specific settings.
Typical Usage Pattern¶
Simple Builder¶
Use OptionsBuilder<T> when you just need a small builder around a plain options class:
public class MyFeatureOptions
{
public bool Enabled { get; set; } = true;
}
public class MyFeatureOptionsBuilder : OptionsBuilder<MyFeatureOptions>
{
public MyFeatureOptionsBuilder Enabled(bool enabled)
{
this.Target.Enabled = enabled;
return this;
}
}
Logger-Aware Builder¶
Use OptionsBase plus OptionsBuilderBase<TOption, TBuilder> when the option object should be able to create loggers:
public class MyProviderOptions : OptionsBase
{
public string Name { get; set; }
}
public class MyProviderOptionsBuilder
: OptionsBuilderBase<MyProviderOptions, MyProviderOptionsBuilder>
{
public MyProviderOptionsBuilder Name(string value)
{
this.Target.Name = value;
return this;
}
}
Where You Will See It¶
This pattern appears across the devkit in package-specific builders for:
- storage providers
- messaging and broker configuration
- startup tasks
- scheduling
- authentication and test helpers
- other infrastructure services with fluent setup APIs
That shared base pattern is what keeps those APIs feeling similar even though they live in different packages.
Relationship To Microsoft.Extensions.Options¶
This package solves a different problem than the built-in options stack.
Use the builder pattern when:
- you want a fluent API for composing a configuration object
- the options object is built once as part of registration
- the package does not need runtime reloading or named options
Use Microsoft.Extensions.Options when:
- you need standard configuration binding across the app
- you need
IOptions<T>,IOptionsSnapshot<T>, orIOptionsMonitor<T> - you want reloadable configuration from files or providers
The two approaches can coexist. The devkit builder pattern is often used to create or refine options during registration, while configuration binding may still happen elsewhere.
Design Guidance¶
- Keep builders small and specific to one package.
- Put shared fluent behavior into the base classes, not into every feature package.
- Use
OptionsBaseonly when logger creation on the options object is genuinely useful. - Avoid turning these builders into mini-frameworks. Their value is simplicity.