Optify is a Roslyn source generator that
wires options pattern types into the generic host:
mark a class or record with [OptifyOptions],
call
UseOptify() on your IHostBuilder, and each type will automatically be bound to configuration based on the type name
or the SectionName attribute.
dotnet add package OptifyMark your configuration types with [OptifyOptions] so registration code is generated at compile time.
IMPORTANT: Types without [OptifyOptions] are not registered by UseOptify().
Apply [OptifyOptions] to types that represent configuration.
using Optify;
// Binds to section "MyAppSettings" by convention - matches class name.
[OptifyOptions]
public class MyAppSettings
{
public string? ApiUrl { get; init; }
}
// Binds to section "ExternalServices" - specified by attribute.
[Optify(SectionName = "ExternalServices")]
public record EmailSettings
{
public string? SmtpHost { get; init; }
}Register every [OptifyOptions] type in the current assembly (recommended; registration is emitted as concrete
calls—no
reflection):
using Optify;
var host = Host.CreateDefaultBuilder(args)
// ...
.UseOptify()
// ...
.Build();With ASP.NET Core minimal hosting, call it on WebApplicationBuilder.Host:
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseOptify();Useful for testing scenarios when you don't want to register all types in the assembly. Avoid this if you have control over your types because this requires reflection.
// No [OptifyOptions] attribute required to register by convention.
public class MyAppSettings
{
public string? ApiUrl { get; init; }
}
// Use attribute to specify a different section name.
[Optify(SectionName = "ExternalServices")]
public record EmailSettings
{
public string? SmtpHost { get; init; }
}
var host = Host.CreateDefaultBuilder(args)
// ...
.UseOptify<MyAppSettings>()
.UseOptify<EmailSettings>()
// ...
.Build();Optify
supports options validation via
the ValidationFlag enum:
| Flag | Effect |
|---|---|
DataAnnotations |
Validates using System.ComponentModel.DataAnnotations attributes. |
OnStart |
Validates eagerly at host startup rather than on first access. |
Flags can be combined with |. There are two ways to configure validation:
Set the Validation property on [OptifyOptions]. This works with both UseOptify() and UseOptify<T>().
using System.ComponentModel.DataAnnotations;
using Optify;
[OptifyOptions(Validation = ValidationFlag.DataAnnotations | ValidationFlag.OnStart)]
public class MyAppSettings
{
[Required]
public string ApiUrl { get; init; } = null!;
}Pass a ValidationFlag to UseOptify() or an OptifyConfiguration to UseOptify<T>() to apply validation to all
registered types.
// Source-generated: applies to all [OptifyOptions] types in the assembly.
var host = Host.CreateDefaultBuilder(args)
.UseOptify(ValidationFlag.DataAnnotations | ValidationFlag.OnStart)
.Build();
// Single type: applies only to MyAppSettings.
var host = Host.CreateDefaultBuilder(args)
.UseOptify<MyAppSettings>(new OptifyConfiguration
{
Validation = ValidationFlag.DataAnnotations | ValidationFlag.OnStart
})
.Build();Flags from the attribute and the registration call are additive — if either specifies DataAnnotations, data annotation
validation is enabled for that type.
When using UseOptify<T>(), the configuration section name is resolved in the following order of precedence:
OptifyConfiguration.SectionName— if provided to the extension method.[OptifyOptions(SectionName = "...")]— if set on the type's attribute.- The type name (e.g.
MyAppSettingsbinds to section"MyAppSettings").
When using the source-generated UseOptify(), only steps 2 and 3 apply since there is no OptifyConfiguration
parameter.
Match your appsettings.json (or other configuration sources) to the resolved section names:
{
"MyAppSettings": {
"ApiUrl": "https://api.example.com"
},
"ExternalServices": {
"SmtpHost": "smtp.example.com"
}
}This project is licensed under the MIT License—see LICENSE.md.