Optiespatroon in .NET
Het optiespatroon maakt gebruik van klassen om sterk getypte toegang te bieden tot groepen gerelateerde instellingen. Wanneer configuratie-instellingen worden geïsoleerd door scenario's in afzonderlijke klassen, voldoet de app aan twee belangrijke principes voor software-engineering:
- Het Interface Segregation Principle (ISP) of Encapsulation: Scenario's (klassen) die afhankelijk zijn van configuratie-instellingen, zijn alleen afhankelijk van de configuratie-instellingen die ze gebruiken.
- Scheiding van problemen: instellingen voor verschillende onderdelen van de app zijn niet afhankelijk of gekoppeld aan elkaar.
Opties bieden ook een mechanisme voor het valideren van configuratiegegevens. Zie de sectie Optiesvalidatie voor meer informatie.
Hiërarchische bindingsconfiguratie
De voorkeursmethode voor het lezen van gerelateerde configuratiewaarden is het gebruik van het optiespatroon. Het optiespatroon is mogelijk via de IOptions<TOptions> interface, waarbij de algemene typeparameter TOptions
wordt beperkt tot een class
. De IOptions<TOptions>
kan later worden verstrekt via afhankelijkheidsinjectie. Zie Afhankelijkheidsinjectie in .NET voor meer informatie.
Als u bijvoorbeeld de gemarkeerde configuratiewaarden wilt lezen uit een appsettings.json-bestand :
{
"SecretKey": "Secret key value",
"TransientFaultHandlingOptions": {
"Enabled": true,
"AutoRetryDelay": "00:00:07"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Maak de volgende TransientFaultHandlingOptions
klasse:
public sealed class TransientFaultHandlingOptions
{
public bool Enabled { get; set; }
public TimeSpan AutoRetryDelay { get; set; }
}
Wanneer u het optiespatroon gebruikt, wordt er een optiesklasse gebruikt:
- Moet niet-abstract zijn met een openbare parameterloze constructor
- Openbare eigenschappen voor lezen/schrijven bevatten om te binden (velden zijn niet gebonden)
De volgende code maakt deel uit van het bestand Program.cs C#en:
- Roept ConfigurationBinder.Bind aan om de
TransientFaultHandlingOptions
klasse aan de"TransientFaultHandlingOptions"
sectie te binden. - Geeft de configuratiegegevens weer.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ConsoleJson.Example;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Configuration.Sources.Clear();
IHostEnvironment env = builder.Environment;
builder.Configuration
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true);
TransientFaultHandlingOptions options = new();
builder.Configuration.GetSection(nameof(TransientFaultHandlingOptions))
.Bind(options);
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
using IHost host = builder.Build();
// Application code should start here.
await host.RunAsync();
// <Output>
// Sample output:
In de voorgaande code heeft het JSON-configuratiebestand de "TransientFaultHandlingOptions"
sectie gebonden aan het TransientFaultHandlingOptions
exemplaar. Hierdoor worden de eigenschappen van C#-objecten gehydrateerd met de bijbehorende waarden uit de configuratie.
ConfigurationBinder.Get<T>
bindt en retourneert het opgegeven type. ConfigurationBinder.Get<T>
kan handiger zijn dan het gebruik.ConfigurationBinder.Bind
De volgende code laat zien hoe u deze kunt gebruiken ConfigurationBinder.Get<T>
met de TransientFaultHandlingOptions
klasse:
var options =
builder.Configuration.GetSection(nameof(TransientFaultHandlingOptions))
.Get<TransientFaultHandlingOptions>();
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
In de voorgaande code wordt het ConfigurationBinder.Get<T>
gebruikt om een exemplaar van het TransientFaultHandlingOptions
object te verkrijgen met de eigenschapswaarden die zijn gevuld met de onderliggende configuratie.
Belangrijk
De ConfigurationBinder klasse bevat verschillende API's, zoals .Bind(object instance)
en .Get<T>()
die niet zijn beperkt tot class
. Wanneer u een van de optiesinterfaces gebruikt, moet u voldoen aan bovengenoemde beperkingen voor optiesklassen.
Een alternatieve benadering bij het gebruik van het optiespatroon is om de "TransientFaultHandlingOptions"
sectie te binden en toe te voegen aan de container van de afhankelijkheidsinjectieservice. In de volgende code TransientFaultHandlingOptions
wordt deze toegevoegd aan de servicecontainer met Configure en gebonden aan de configuratie:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.Configure<TransientFaultHandlingOptions>(
builder.Configuration.GetSection(
key: nameof(TransientFaultHandlingOptions)));
Het builder
in het voorgaande voorbeeld is een instantie van HostApplicationBuilder.
Tip
De key
parameter is de naam van de configuratiesectie die moet worden gezocht. Deze hoeft niet overeen te komen met de naam van het type dat het vertegenwoordigt. U kunt bijvoorbeeld een sectie met de naam "FaultHandling"
hebben en deze kan worden vertegenwoordigd door de TransientFaultHandlingOptions
klasse. In dit geval geeft u in plaats daarvan de GetSection functie door"FaultHandling"
. De nameof
operator wordt gebruikt als gemak wanneer de benoemde sectie overeenkomt met het type waarmee deze overeenkomt.
Met behulp van de voorgaande code leest de volgende code de positieopties:
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public sealed class ExampleService(IOptions<TransientFaultHandlingOptions> options)
{
private readonly TransientFaultHandlingOptions _options = options.Value;
public void DisplayValues()
{
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={_options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={_options.AutoRetryDelay}");
}
}
In de voorgaande code worden wijzigingen in het JSON-configuratiebestand nadat de app is gestart, niet gelezen. Als u wijzigingen wilt lezen nadat de app is gestart, gebruikt u IOptionsSnapshot of IOptionsMonitor om wijzigingen te controleren wanneer deze optreden en reageert u dienovereenkomstig.
Optiesinterfaces
- Biedt geen ondersteuning voor:
- Het lezen van configuratiegegevens nadat de app is gestart.
- Benoemde opties
- Is geregistreerd als een Singleton en kan worden geïnjecteerd in elke levensduur van de service.
- Is handig in scenario's waarin opties opnieuw moeten worden gecomputeerd op elke injectieresolutie, binnen een bereik of tijdelijke levensduur. Zie IOptionsSnapshot gebruiken om bijgewerkte gegevens te lezen voor meer informatie.
- Is geregistreerd als Scoped en kan daarom niet worden opgenomen in een Singleton-service.
- Ondersteunt benoemde opties
- Wordt gebruikt om opties op te halen en optiesmeldingen voor
TOptions
exemplaren te beheren. - Is geregistreerd als een Singleton en kan worden geïnjecteerd in elke levensduur van de service.
- Ondersteunt:
- Meldingen wijzigen
- Benoemde opties
- Herlaadbare configuratie
- Ongeldige opties voor selectief (IOptionsMonitorCache<TOptions>)
IOptionsFactory<TOptions> is verantwoordelijk voor het maken van nieuwe opties instanties. Het heeft één Create methode. De standaard implementatie neemt alle geregistreerde IConfigureOptions<TOptions> en IPostConfigureOptions<TOptions> voert eerst alle configuraties uit, gevolgd door de postconfiguratie. Er wordt onderscheid gemaakt tussen IConfigureNamedOptions<TOptions> en IConfigureOptions<TOptions> wordt alleen de juiste interface aanroepen.
IOptionsMonitorCache<TOptions> wordt gebruikt voor IOptionsMonitor<TOptions> het opslaan van exemplaren in de cache TOptions
. De IOptionsMonitorCache<TOptions> opties in de monitor worden ongeldig, zodat de waarde opnieuw wordt gecomputeerd (TryRemove). Waarden kunnen handmatig worden geïntroduceerd met TryAdd. De Clear methode wordt gebruikt wanneer alle benoemde exemplaren op aanvraag opnieuw moeten worden gemaakt.
IOptionsChangeTokenSource<TOptions> wordt gebruikt voor het ophalen van de IChangeToken wijzigingen in het onderliggende TOptions
exemplaar. Zie Wijzigingsmeldingen voor meer informatie over wijzigingstokenprimitief.
Voordelen van optiesinterfaces
Met behulp van een algemeen wrappertype kunt u de levensduur van de optie loskoppelen van de afhankelijkheidsinjectiecontainer (DI). De IOptions<TOptions>.Value interface biedt een abstractielaag, inclusief algemene beperkingen, voor uw optiestype. Dit biedt de volgende voordelen:
- De evaluatie van het
T
configuratie-exemplaar wordt uitgesteld tot het openen van IOptions<TOptions>.Value, in plaats van wanneer het wordt geïnjecteerd. Dit is belangrijk omdat u deT
optie op verschillende plaatsen kunt gebruiken en de semantiek van de levensduur kunt kiezen zonder dat u iets hoeft teT
wijzigen. - Bij het registreren van opties van het type
T
hoeft u hetT
type niet expliciet te registreren. Dit is handig wanneer u een bibliotheek met eenvoudige standaardinstellingen ontwerpt en u niet wilt afdwingen dat de aanroeper opties registreert in de DI-container met een specifieke levensduur. - Vanuit het perspectief van de API is het mogelijk beperkingen voor het type
T
toe te staan (in dit gevalT
is dit beperkt tot een verwijzingstype).
IOptionsSnapshot gebruiken om bijgewerkte gegevens te lezen
Wanneer u gebruikt IOptionsSnapshot<TOptions>, worden opties eenmaal per aanvraag berekend wanneer deze worden geopend en in de cache worden opgeslagen voor de levensduur van de aanvraag. Wijzigingen in de configuratie worden gelezen nadat de app wordt gestart bij het gebruik van configuratieproviders die ondersteuning bieden voor het lezen van bijgewerkte configuratiewaarden.
Het verschil tussen IOptionsMonitor
en IOptionsSnapshot
is dat:
IOptionsMonitor
is een singleton-service waarmee de huidige optiewaarden op elk gewenst moment worden opgehaald, wat met name handig is in singleton-afhankelijkheden.IOptionsSnapshot
is een scoped service en biedt een momentopname van de opties op het moment dat hetIOptionsSnapshot<T>
object wordt samengesteld. Momentopnamen van opties zijn ontworpen voor gebruik met tijdelijke en bereikafhankelijkheden.
In de volgende code wordt gebruikgemaakt van IOptionsSnapshot<TOptions>.
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public sealed class ScopedService(IOptionsSnapshot<TransientFaultHandlingOptions> options)
{
private readonly TransientFaultHandlingOptions _options = options.Value;
public void DisplayValues()
{
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={_options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={_options.AutoRetryDelay}");
}
}
Met de volgende code wordt een configuratie-exemplaar geregistreerd waarmee TransientFaultHandlingOptions
een binding wordt uitgevoerd:
builder.Services
.Configure<TransientFaultHandlingOptions>(
configurationRoot.GetSection(
nameof(TransientFaultHandlingOptions)));
In de voorgaande code wordt de Configure<TOptions>
methode gebruikt om een configuratie-exemplaar te registreren waarmee TOptions
een verbinding wordt uitgevoerd en worden de opties bijgewerkt wanneer de configuratie wordt gewijzigd.
IOptionsMonitor
Het IOptionsMonitor
type ondersteunt wijzigingsmeldingen en maakt scenario's mogelijk waarin uw app dynamisch moet reageren op wijzigingen in de configuratiebron. Dit is handig wanneer u moet reageren op wijzigingen in configuratiegegevens nadat de app is gestart. Wijzigingsmeldingen worden alleen ondersteund voor configuratieproviders op basis van een bestandssysteem, zoals de volgende:
- Microsoft.Extensions.Configuration.Ini
- Microsoft.Extensions.Configuration.Json
- Microsoft.Extensions.Configuration.KeyPerFile
- Microsoft.Extensions.Configuration.UserSecrets
- Microsoft.Extensions.Configuration.Xml
Als u de optiesmonitor wilt gebruiken, worden optiesobjecten op dezelfde manier geconfigureerd vanuit een configuratiesectie.
builder.Services
.Configure<TransientFaultHandlingOptions>(
configurationRoot.GetSection(
nameof(TransientFaultHandlingOptions)));
In het volgende voorbeeld wordt gebruikgemaakt van IOptionsMonitor<TOptions>:
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public sealed class MonitorService(IOptionsMonitor<TransientFaultHandlingOptions> monitor)
{
public void DisplayValues()
{
TransientFaultHandlingOptions options = monitor.CurrentValue;
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
}
}
In de voorgaande code worden wijzigingen in het JSON-configuratiebestand gewijzigd nadat de app is gestart.
Tip
Sommige bestandssystemen, zoals Docker-containers en netwerkshares, verzenden mogelijk niet betrouwbaar wijzigingsmeldingen. Wanneer u de IOptionsMonitor<TOptions> interface in deze omgevingen gebruikt, stelt u de DOTNET_USE_POLLING_FILE_WATCHER
omgevingsvariabele 1
in op of true
pollt u het bestandssysteem op wijzigingen. Het interval waarmee wijzigingen worden gecontroleerd, is elke vier seconden en kan niet worden geconfigureerd.
Zie Een .NET-app containeriseren voor meer informatie over Docker-containers.
Ondersteuning voor benoemde opties met IConfigureNamedOptions
Benoemde opties:
- Dit is handig wanneer meerdere configuratiesecties verbinding maken met dezelfde eigenschappen.
- Zijn hoofdlettergevoelig.
Houd rekening met het volgende appsettings.json-bestand :
{
"Features": {
"Personalize": {
"Enabled": true,
"ApiKey": "aGEgaGEgeW91IHRob3VnaHQgdGhhdCB3YXMgcmVhbGx5IHNvbWV0aGluZw=="
},
"WeatherStation": {
"Enabled": true,
"ApiKey": "QXJlIHlvdSBhdHRlbXB0aW5nIHRvIGhhY2sgdXM/"
}
}
}
In plaats van twee klassen te maken om te binden Features:Personalize
en Features:WeatherStation
wordt de volgende klasse gebruikt voor elke sectie:
public class Features
{
public const string Personalize = nameof(Personalize);
public const string WeatherStation = nameof(WeatherStation);
public bool Enabled { get; set; }
public string ApiKey { get; set; }
}
Met de volgende code worden de benoemde opties geconfigureerd:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// Omitted for brevity...
builder.Services.Configure<Features>(
Features.Personalize,
builder.Configuration.GetSection("Features:Personalize"));
builder.Services.Configure<Features>(
Features.WeatherStation,
builder.Configuration.GetSection("Features:WeatherStation"));
Met de volgende code worden de benoemde opties weergegeven:
public sealed class Service
{
private readonly Features _personalizeFeature;
private readonly Features _weatherStationFeature;
public Service(IOptionsSnapshot<Features> namedOptionsAccessor)
{
_personalizeFeature = namedOptionsAccessor.Get(Features.Personalize);
_weatherStationFeature = namedOptionsAccessor.Get(Features.WeatherStation);
}
}
Alle opties zijn benoemde exemplaren. IConfigureOptions<TOptions>exemplaren worden behandeld als gericht op het Options.DefaultName
exemplaar.string.Empty
IConfigureNamedOptions<TOptions> implementeert IConfigureOptions<TOptions>ook . De standaard implementatie van de IOptionsFactory<TOptions> bevat logica om elk op de juiste manier te gebruiken. De null
benoemde optie wordt gebruikt om alle benoemde exemplaren te targeten in plaats van op een specifiek benoemd exemplaar. ConfigureAll en PostConfigureAll gebruik deze conventie.
OptionsBuilder-API
OptionsBuilder<TOptions> wordt gebruikt voor het configureren van TOptions
exemplaren. OptionsBuilder
stroomlijnt het maken van benoemde opties, omdat het slechts één parameter is voor de eerste AddOptions<TOptions>(string optionsName)
aanroep in plaats van in alle volgende aanroepen weer te geven. Optiesvalidatie en de ConfigureOptions
overbelastingen die serviceafhankelijkheden accepteren, zijn alleen beschikbaar via OptionsBuilder
.
OptionsBuilder
wordt gebruikt in de sectie Optiesvalidatie .
DI-services gebruiken om opties te configureren
Wanneer u opties configureert, kunt u afhankelijkheidsinjectie gebruiken voor toegang tot geregistreerde services en deze gebruiken om opties te configureren. Dit is handig wanneer u toegang nodig hebt tot services om opties te configureren. Services kunnen op twee manieren worden geopend vanuit DI tijdens het configureren van opties:
Geef een configuratiedelegatie door om te configureren op OptionsBuilder<TOptions>.
OptionsBuilder<TOptions>
biedt overbelastingen van Configureren waarmee maximaal vijf services kunnen worden gebruikt om opties te configureren:builder.Services .AddOptions<MyOptions>("optionalName") .Configure<ExampleService, ScopedService, MonitorService>( (options, es, ss, ms) => options.Property = DoSomethingWith(es, ss, ms));
Maak een type dat het type als een service implementeert IConfigureOptions<TOptions> of IConfigureNamedOptions<TOptions> registreert.
Het is raadzaam om een configuratie-gemachtigde door te geven aan Configureren, omdat het maken van een service complexer is. Het maken van een type is gelijk aan wat het framework doet bij het aanroepen van Configureren. Met Aanroepen configureren registreert een tijdelijke algemene IConfigureNamedOptions<TOptions>, die een constructor heeft die de algemene servicetypen accepteert die zijn opgegeven.
Validatie van opties
Met optiesvalidatie kunnen optiewaarden worden gevalideerd.
Houd rekening met het volgende appsettings.json-bestand :
{
"MyCustomSettingsSection": {
"SiteTitle": "Amazing docs from Awesome people!",
"Scale": 10,
"VerbosityLevel": 32
}
}
De volgende klasse bindt aan de "MyCustomSettingsSection"
configuratiesectie en past een aantal DataAnnotations
regels toe:
using System.ComponentModel.DataAnnotations;
namespace ConsoleJson.Example;
public sealed class SettingsOptions
{
public const string ConfigurationSectionName = "MyCustomSettingsSection";
[Required]
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public required string SiteTitle { get; set; }
[Required]
[Range(0, 1_000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public required int Scale { get; set; }
[Required]
public required int VerbosityLevel { get; set; }
}
In de voorgaande SettingsOptions
klasse bevat de ConfigurationSectionName
eigenschap de naam van de configuratiesectie waaraan moet worden gekoppeld. In dit scenario bevat het optiesobject de naam van de configuratiesectie.
Tip
De naam van de configuratiesectie is onafhankelijk van het configuratieobject waaraan het is gebonden. Met andere woorden, een configuratiesectie met de naam "FooBarOptions"
kan worden gebonden aan een optiesobject met de naam ZedOptions
. Hoewel het misschien gebruikelijk is om ze dezelfde naam te geven, is het niet nodig en kan het naamconflicten daadwerkelijk veroorzaken.
De volgende code:
- Oproepen AddOptions om een OptionsBuilder<TOptions> op te halen die aan de
SettingsOptions
klasse wordt gekoppeld. - Aanroepen ValidateDataAnnotations om validatie in te schakelen met behulp van
DataAnnotations
.
builder.Services
.AddOptions<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations();
De ValidateDataAnnotations
extensiemethode wordt gedefinieerd in het NuGet-pakket Microsoft.Extensions.Options.DataAnnotations .
De volgende code geeft de configuratiewaarden weer of rapporteert validatiefouten:
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public sealed class ValidationService
{
private readonly ILogger<ValidationService> _logger;
private readonly IOptions<SettingsOptions> _config;
public ValidationService(
ILogger<ValidationService> logger,
IOptions<SettingsOptions> config)
{
_config = config;
_logger = logger;
try
{
SettingsOptions options = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (string failure in ex.Failures)
{
_logger.LogError("Validation error: {FailureMessage}", failure);
}
}
}
}
Met de volgende code wordt een complexere validatieregel toegepast met behulp van een gemachtigde:
builder.Services
.AddOptions<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Scale != 0)
{
return config.VerbosityLevel > config.Scale;
}
return true;
}, "VerbosityLevel must be > than Scale.");
De validatie vindt plaats tijdens runtime, maar u kunt deze zo configureren dat deze wordt uitgevoerd bij het opstarten door in plaats daarvan een aanroep te koppelen aan ValidateOnStart
:
builder.Services
.AddOptions<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Scale != 0)
{
return config.VerbosityLevel > config.Scale;
}
return true;
}, "VerbosityLevel must be > than Scale.")
.ValidateOnStart();
Vanaf .NET 8 kunt u een alternatieve API gebruiken, AddOptionsWithValidateOnStart<TOptions>(IServiceCollection, String)waarmee validatie wordt ingeschakeld voor een specifiek type opties:
builder.Services
.AddOptionsWithValidateOnStart<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Scale != 0)
{
return config.VerbosityLevel > config.Scale;
}
return true;
}, "VerbosityLevel must be > than Scale.");
IValidateOptions
voor complexe validatie
De volgende klasse implementeert IValidateOptions<TOptions>:
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
sealed partial class ValidateSettingsOptions(
IConfiguration config)
: IValidateOptions<SettingsOptions>
{
public SettingsOptions? Settings { get; private set; } =
config.GetSection(SettingsOptions.ConfigurationSectionName)
.Get<SettingsOptions>();
public ValidateOptionsResult Validate(string? name, SettingsOptions options)
{
StringBuilder? failure = null;
if (!ValidationRegex().IsMatch(options.SiteTitle))
{
(failure ??= new()).AppendLine($"{options.SiteTitle} doesn't match RegEx");
}
if (options.Scale is < 0 or > 1_000)
{
(failure ??= new()).AppendLine($"{options.Scale} isn't within Range 0 - 1000");
}
if (Settings is { Scale: 0 } && Settings.VerbosityLevel <= Settings.Scale)
{
(failure ??= new()).AppendLine("VerbosityLevel must be > than Scale.");
}
return failure is not null
? ValidateOptionsResult.Fail(failure.ToString())
: ValidateOptionsResult.Success;
}
[GeneratedRegex("^[a-zA-Z''-'\\s]{1,40}$")]
private static partial Regex ValidationRegex();
}
IValidateOptions
schakelt het verplaatsen van de validatiecode naar een klasse in.
Notitie
Deze voorbeeldcode is afhankelijk van het NuGet-pakket Microsoft.Extensions.Configuration.Json .
Met behulp van de voorgaande code wordt validatie ingeschakeld bij het configureren van services met de volgende code:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// Omitted for brevity...
builder.Services.Configure<SettingsOptions>(
builder.Configuration.GetSection(
SettingsOptions.ConfigurationSectionName));
builder.Services.TryAddEnumerable(
ServiceDescriptor.Singleton
<IValidateOptions<SettingsOptions>, ValidateSettingsOptions>());
Opties na configuratie
Stel na de configuratie in met IPostConfigureOptions<TOptions>. Na de configuratie wordt uitgevoerd nadat alle IConfigureOptions<TOptions> configuraties zijn uitgevoerd en kan dit handig zijn in scenario's waarin u de configuratie moet overschrijven:
builder.Services.PostConfigure<CustomOptions>(customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});
PostConfigure is beschikbaar voor het na configureren van benoemde opties:
builder.Services.PostConfigure<CustomOptions>("named_options_1", customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});
Gebruik PostConfigureAll dit om alle configuratie-exemplaren na de configuratie te configureren:
builder.Services.PostConfigureAll<CustomOptions>(customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});