Vzor možností v ASP.NET Core
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Vzor možností používá třídy k zajištění přístupu silného typu ke skupinám souvisejících nastavení. Pokud jsou nastavení konfigurace izolované podle scénáře do samostatných tříd, aplikace dodržuje dva důležité principy softwarového inženýrství:
- Zapouzdření:
- Třídy, které závisí na nastavení konfigurace, závisí pouze na nastavení konfigurace, která používají.
- Oddělení obav:
- Nastavení pro různé části aplikace nejsou závislá ani vzájemně svázaná.
Možnosti také poskytují mechanismus pro ověření konfiguračních dat. Další informace najdete v části Možnosti ověření .
Tento článek obsahuje informace o vzoru možností v ASP.NET Core. Informace o použití vzoru možností v konzolových aplikacích najdete v tématu Možnosti v .NET.
Vytvoření vazby hierarchické konfigurace
Upřednostňovaným způsobem čtení souvisejících hodnot konfigurace je použití vzoru možností. Pokud chcete například přečíst následující konfigurační hodnoty:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Vytvořte následující třídu PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
Třída možností:
- Nesmí být abstraktní.
- Má veřejné vlastnosti pro čtení i zápis typu, které mají odpovídající položky v konfiguraci jsou svázané.
- Má vlastnosti pro čtení i zápis vázané na odpovídající položky v konfiguraci.
- Neobsahuje svá pole svázaná. V předchozím kódu není pole
Position
vázáno. PolePosition
se používá, aby řetězec"Position"
nemusel být v aplikaci pevně zakódován při vytváření vazby třídy na zprostředkovatele konfigurace.
Následující kód:
- Zavolá metodu ConfigurationBinder.Bind pro svázání třídy
PositionOptions
s oddílemPosition
. - Zobrazí konfigurační data pole
Position
.
public class Test22Model : PageModel
{
private readonly IConfiguration Configuration;
public Test22Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
ConfigurationBinder.Get<T>
naváže a vrátí určený typ. ConfigurationBinder.Get<T>
může být pohodlnější než použití ConfigurationBinder.Bind
. Následující kód ukazuje, jak používat ConfigurationBinder.Get<T>
s třídou PositionOptions
:
public class Test21Model : PageModel
{
private readonly IConfiguration Configuration;
public PositionOptions? positionOptions { get; private set; }
public Test21Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
positionOptions = Configuration.GetSection(PositionOptions.Position)
.Get<PositionOptions>();
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
Bind také umožňuje zřetězení abstraktní třídy. Vezměte v úvahu následující kód, který používá abstraktní třídu SomethingWithAName
:
namespace ConfigSample.Options;
public abstract class SomethingWithAName
{
public abstract string? Name { get; set; }
}
public class NameTitleOptions(int age) : SomethingWithAName
{
public const string NameTitle = "NameTitle";
public override string? Name { get; set; }
public string Title { get; set; } = string.Empty;
public int Age { get; set; } = age;
}
Následující kód zobrazí NameTitleOptions
konfigurační hodnoty:
public class Test33Model : PageModel
{
private readonly IConfiguration Configuration;
public Test33Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var nameTitleOptions = new NameTitleOptions(22);
Configuration.GetSection(NameTitleOptions.NameTitle).Bind(nameTitleOptions);
return Content($"Title: {nameTitleOptions.Title} \n" +
$"Name: {nameTitleOptions.Name} \n" +
$"Age: {nameTitleOptions.Age}"
);
}
}
Bind
Volání jsou méně striktní než volání:Get<>
Bind
umožňuje zřetězení abstraktního objektu.Get<>
aplikace musí vytvořit samotnou instanci.
Vzor Možností
Alternativním přístupem při používání vzoru možností je vytvoření vazby oddílu Position
a jeho přidání do kontejneru služby vkládání závislostí. V následujícím kódu se PositionOptions
přidá do kontejneru služby s příkazem Configure a sváže se s konfigurací:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
Pomocí předchozího kódu přečte následující kód možnosti pozice:
public class Test2Model : PageModel
{
private readonly PositionOptions _options;
public Test2Model(IOptions<PositionOptions> options)
{
_options = options.Value;
}
public ContentResult OnGet()
{
return Content($"Title: {_options.Title} \n" +
$"Name: {_options.Name}");
}
}
V předchozím kódu se změny konfiguračního souboru JSON po spuštění aplikace nepřečtou. Pokud chcete po spuštění aplikace přečíst změny, použijte IOptionsSnapshot.
Rozhraní možností
- Nepodporuje:
- Čtení konfiguračních dat po spuštění aplikace
- Pojmenované možnosti
- Je registrován jako Singleton a může být vložen do jakékoli životnosti služby.
- Je užitečné ve scénářích, ve kterých by se měly přepočítat možnosti pro každý požadavek. Další informace najdete v tématu Použití IOptionsSnapshot ke čtení aktualizovaných dat.
- Je zaregistrovaný jako Obor, a proto se nedá vložit do služby Singleton.
- Podporuje pojmenované možnosti.
- Slouží k načtení možností a správě oznámení možností pro
TOptions
instance. - Je registrován jako Singleton a může být vložen do jakékoli životnosti služby.
- Podporuje:
- Změna oznámení
- pojmenované možnosti
- Znovu načístelná konfigurace
- Zrušení selektivních možností (IOptionsMonitorCache<TOptions>)
Scénáře po konfiguraci umožňují nastavení nebo změnu možností po dokončení konfigurace IConfigureOptions<TOptions> .
IOptionsFactory<TOptions> zodpovídá za vytváření nových instancí možností. Má jednu Create metodu. Výchozí implementace vezme všechny registrované IConfigureOptions<TOptions> a IPostConfigureOptions<TOptions> nejprve spustí všechny konfigurace, za kterými následuje po konfiguraci. Rozlišuje mezi IConfigureNamedOptions<TOptions> rozhraním a IConfigureOptions<TOptions> volá pouze příslušné rozhraní.
IOptionsMonitorCache<TOptions> používá IOptionsMonitor<TOptions> se k ukládání instancí do mezipaměti TOptions
. Instance IOptionsMonitorCache<TOptions> možností v monitorování zneplatní, aby byla hodnota přepočítána (TryRemove). Hodnoty lze ručně zavést s TryAdd. Metoda Clear se používá, když se všechny pojmenované instance mají znovu vytvořit na vyžádání.
Čtení aktualizovaných dat pomocí IOptionsSnapshot
Pomocí IOptionsSnapshot<TOptions>:
- Možnosti se po dobu životnosti požadavku počítají jednou za požadavek a ukládají se do mezipaměti.
- Může dojít k významnému snížení výkonu, protože se jedná o službu s vymezeným oborem, která se přepočítá na každou žádost. Další informace najdete v tomto problému na GitHubu a vylepšete výkon vazby konfigurace.
- Změny konfigurace se čtou po spuštění aplikace při použití zprostředkovatelů konfigurace, kteří podporují čtení aktualizovaných konfiguračních hodnot.
Rozdíl mezi IOptionsMonitor
a IOptionsSnapshot
je následující:
IOptionsMonitor
je služba Singleton, která načítá aktuální hodnoty možností kdykoli, což je zvlášť užitečné v jednoúčelových závislostech.IOptionsSnapshot
je služba s vymezeným oborem a poskytuje snímek možností v době,IOptionsSnapshot<T>
kdy je objekt vytvořen. Snímky možností jsou navržené pro použití s přechodnými a vymezenými závislostmi.
Následující kód používá IOptionsSnapshot<TOptions>.
public class TestSnapModel : PageModel
{
private readonly MyOptions _snapshotOptions;
public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
{
_snapshotOptions = snapshotOptionsAccessor.Value;
}
public ContentResult OnGet()
{
return Content($"Option1: {_snapshotOptions.Option1} \n" +
$"Option2: {_snapshotOptions.Option2}");
}
}
Následující kód zaregistruje instanci konfigurace, která MyOptions
se sváže s:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
V předchozím kódu se změny konfiguračního souboru JSON po spuštění aplikace načtou.
IOptionsMonitor
Následující kód zaregistruje instanci konfigurace, která MyOptions
je svázaná s.
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
Následující příklad používá IOptionsMonitor<TOptions>:
public class TestMonitorModel : PageModel
{
private readonly IOptionsMonitor<MyOptions> _optionsDelegate;
public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
{
_optionsDelegate = optionsDelegate;
}
public ContentResult OnGet()
{
return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
$"Option2: {_optionsDelegate.CurrentValue.Option2}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
Podpora pojmenovaných možností pomocí IConfigureNamedOptions
Pojmenované možnosti:
- Jsou užitečné, když se několik oddílů konfigurace sváže se stejnými vlastnostmi.
- Rozlišují se malá a velká písmena.
Vezměme například následující soubor appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Místo vytvoření dvou tříd pro vytvoření vazby TopItem:Month
a TopItem:Year
pro každou část se používá následující třída:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
}
Následující kód nakonfiguruje pojmenované možnosti:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
var app = builder.Build();
Následující kód zobrazí pojmenované možnosti:
public class TestNOModel : PageModel
{
private readonly TopItemSettings _monthTopItem;
private readonly TopItemSettings _yearTopItem;
public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
{
_monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
_yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
}
public ContentResult OnGet()
{
return Content($"Month:Name {_monthTopItem.Name} \n" +
$"Month:Model {_monthTopItem.Model} \n\n" +
$"Year:Name {_yearTopItem.Name} \n" +
$"Year:Model {_yearTopItem.Model} \n" );
}
}
Všechny možnosti jsou pojmenované instance. IConfigureOptions<TOptions> instance jsou považovány za cíl instance Options.DefaultName
, což je string.Empty
. IConfigureNamedOptions<TOptions> implementuje IConfigureOptions<TOptions>také . Výchozí implementace má logiku IOptionsFactory<TOptions> , která se má použít odpovídajícím způsobem. Pojmenovaná null
možnost se používá k cílení na všechny pojmenované instance místo na konkrétní pojmenovanou instanci. ConfigureAll a PostConfigureAll používat tuto konvenci.
OptionsBuilder API
OptionsBuilder<TOptions> slouží ke konfiguraci TOptions
instancí. OptionsBuilder
zjednodušuje vytváření pojmenovaných možností, protože se jedná pouze o jediný parametr počátečního AddOptions<TOptions>(string optionsName)
volání místo toho, aby se zobrazoval ve všech následných voláních. Možnosti ověřování a ConfigureOptions
přetížení, která přijímají závislosti služby, jsou k dispozici pouze prostřednictvím OptionsBuilder
.
OptionsBuilder
se používá v části Ověřování možností.
Informace o přidání vlastního úložiště najdete v tématu Použití addOptions ke konfiguraci vlastního úložiště .
Konfigurace možností pomocí služeb DI
Ke službám je možné přistupovat prostřednictvím injektáže závislostí a současně konfigurovat možnosti dvěma způsoby:
Předat delegáta konfigurace zapnuto Configure OptionsBuilder<TOptions>.
OptionsBuilder<TOptions>
poskytuje přetížení Configure , která umožňují použití až pěti služeb ke konfiguraci možností:builder.Services.AddOptions<MyOptions>("optionalName") .Configure<Service1, Service2, Service3, Service4, Service5>( (o, s, s2, s3, s4, s5) => o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Vytvořte typ, který implementuje IConfigureOptions<TOptions> nebo IConfigureNamedOptions<TOptions> zaregistruje typ jako službu.
Doporučujeme předat delegáta Configurekonfigurace , protože vytvoření služby je složitější. Vytvoření typu je ekvivalentní tomu, co architektura dělá při volání Configure. Volání Configure registruje přechodný obecný IConfigureNamedOptions<TOptions>, který má konstruktor, který přijímá obecné typy služby zadané.
Ověřování možností
Ověření možností umožňuje ověření hodnot možností.
Vezměme například následující soubor appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Následující třída se používá k vytvoření vazby k oddílu "MyConfig"
konfigurace a používá několik DataAnnotations
pravidel:
public class MyConfigOptions
{
public const string MyConfig = "MyConfig";
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public string Key1 { get; set; }
[Range(0, 1000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Key2 { get; set; }
public int Key3 { get; set; }
}
Následující kód:
- Volání AddOptions pro získání OptionsBuilder<TOptions> vazby ke
MyConfigOptions
třídě - Volání ValidateDataAnnotations pro povolení ověřování pomocí
DataAnnotations
.
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations();
var app = builder.Build();
Metoda ValidateDataAnnotations
rozšíření je definována v balíčku NuGet Microsoft.Extensions.Options.DataAnnotations . U webových aplikací, které používají Microsoft.NET.Sdk.Web
sadu SDK, se tento balíček implicitně odkazuje ze sdílené architektury.
Následující kód zobrazí konfigurační hodnoty nebo chyby ověření:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptions<MyConfigOptions> _config;
public HomeController(IOptions<MyConfigOptions> config,
ILogger<HomeController> logger)
{
_config = config;
_logger = logger;
try
{
var configValue = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (var failure in ex.Failures)
{
_logger.LogError(failure);
}
}
}
public ContentResult Index()
{
string msg;
try
{
msg = $"Key1: {_config.Value.Key1} \n" +
$"Key2: {_config.Value.Key2} \n" +
$"Key3: {_config.Value.Key3}";
}
catch (OptionsValidationException optValEx)
{
return Content(optValEx.Message);
}
return Content(msg);
}
Následující kód používá složitější ověřovací pravidlo pomocí delegáta:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Key2 != 0)
{
return config.Key3 > config.Key2;
}
return true;
}, "Key3 must be > than Key2."); // Failure message.
var app = builder.Build();
IValidateOptions<TOptions>
a IValidatableObject
Následující třída implementuje IValidateOptions<TOptions>:
public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
public MyConfigOptions _config { get; private set; }
public MyConfigValidation(IConfiguration config)
{
_config = config.GetSection(MyConfigOptions.MyConfig)
.Get<MyConfigOptions>();
}
public ValidateOptionsResult Validate(string name, MyConfigOptions options)
{
string? vor = null;
var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
var match = rx.Match(options.Key1!);
if (string.IsNullOrEmpty(match.Value))
{
vor = $"{options.Key1} doesn't match RegEx \n";
}
if ( options.Key2 < 0 || options.Key2 > 1000)
{
vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
}
if (_config.Key2 != default)
{
if(_config.Key3 <= _config.Key2)
{
vor += "Key3 must be > than Key2.";
}
}
if (vor != null)
{
return ValidateOptionsResult.Fail(vor);
}
return ValidateOptionsResult.Success;
}
}
IValidateOptions
umožňuje přesunout ověřovací kód mimo Program.cs
třídu a do třídy.
Pomocí předchozího kódu je ověřování povoleno Program.cs
pomocí následujícího kódu:
using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
MyConfigOptions.MyConfig));
builder.Services.AddSingleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>();
var app = builder.Build();
Ověřování možností také podporuje IValidatableObject. Ověření třídy v rámci samotné třídy:
- Implementujte
IValidatableObject
rozhraní a jeho Validate metodu v rámci třídy. - Zavolat ValidateDataAnnotations .
Program.cs
ValidateOnStart
Při prvním TOption
vytvoření instance se spustí ověření možností. To například znamená, že když dojde k prvnímu přístupu v IOptionsSnapshot<TOptions>.Value
kanálu požadavku nebo když je volána v nastavení, která IOptionsMonitor<TOptions>.Get(string)
jsou přítomna. Po opětovném načtení nastavení se ověření spustí znovu. Modul runtime ASP.NET Core používá OptionsCache<TOptions> k uložení instance možností do mezipaměti po jeho vytvoření.
Pokud chcete spouštět možnosti ověřování dychtivě, zavolejte ValidateOnStart<TOptions>(OptionsBuilder<TOptions>)Program.cs
při spuštění aplikace:
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
Možnosti po konfiguraci
Nastavte po konfiguraci pomocí parametru IPostConfigureOptions<TOptions>. Po dokončení konfigurace se spustí po dokončení konfigurace IConfigureOptions<TOptions> :
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
PostConfigure je k dispozici pro pokonfigurované pojmenované možnosti:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
myOptions.Name = "post_configured_name_value";
myOptions.Model = "post_configured_model_value";
});
var app = builder.Build();
Slouží PostConfigureAll k následné konfiguraci všech instancí konfigurace:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
Možnosti aplikace Access v aplikaci Program.cs
Pokud chcete získat přístup nebo IOptions<TOptions> IOptionsMonitor<TOptions> v Program.cs
aplikaci, zavolejteGetRequiredService:WebApplication.Services
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
Další materiály
Vzor možností používá třídy k zajištění přístupu silného typu ke skupinám souvisejících nastavení. Pokud jsou nastavení konfigurace izolované podle scénáře do samostatných tříd, aplikace dodržuje dva důležité principy softwarového inženýrství:
- Zapouzdření:
- Třídy, které závisí na nastavení konfigurace, závisí pouze na nastavení konfigurace, která používají.
- Oddělení obav:
- Nastavení pro různé části aplikace nejsou závislá ani vzájemně svázaná.
Možnosti také poskytují mechanismus pro ověření konfiguračních dat. Další informace najdete v části Možnosti ověření .
Tento článek obsahuje informace o vzoru možností v ASP.NET Core. Informace o použití vzoru možností v konzolových aplikacích najdete v tématu Možnosti v .NET.
Vytvoření vazby hierarchické konfigurace
Upřednostňovaným způsobem čtení souvisejících hodnot konfigurace je použití vzoru možností. Pokud chcete například přečíst následující konfigurační hodnoty:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Vytvořte následující třídu PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
Třída možností:
- Musí být neabstraktní s veřejným konstruktorem bez parametrů.
- Všechny veřejné vlastnosti pro čtení i zápis typu jsou vázané.
- Pole nejsou vázaná. V předchozím kódu není pole
Position
vázáno. PolePosition
se používá, aby řetězec"Position"
nemusel být v aplikaci pevně zakódován při vytváření vazby třídy na zprostředkovatele konfigurace.
Následující kód:
- Zavolá metodu ConfigurationBinder.Bind pro svázání třídy
PositionOptions
s oddílemPosition
. - Zobrazí konfigurační data pole
Position
.
public class Test22Model : PageModel
{
private readonly IConfiguration Configuration;
public Test22Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
ConfigurationBinder.Get<T>
naváže a vrátí určený typ. ConfigurationBinder.Get<T>
může být pohodlnější než použití ConfigurationBinder.Bind
. Následující kód ukazuje, jak používat ConfigurationBinder.Get<T>
s třídou PositionOptions
:
public class Test21Model : PageModel
{
private readonly IConfiguration Configuration;
public PositionOptions? positionOptions { get; private set; }
public Test21Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
positionOptions = Configuration.GetSection(PositionOptions.Position)
.Get<PositionOptions>();
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
Alternativním přístupem při používání vzoru možností je vytvoření vazby oddílu Position
a jeho přidání do kontejneru služby vkládání závislostí. V následujícím kódu se PositionOptions
přidá do kontejneru služby s příkazem Configure a sváže se s konfigurací:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
Pomocí předchozího kódu přečte následující kód možnosti pozice:
public class Test2Model : PageModel
{
private readonly PositionOptions _options;
public Test2Model(IOptions<PositionOptions> options)
{
_options = options.Value;
}
public ContentResult OnGet()
{
return Content($"Title: {_options.Title} \n" +
$"Name: {_options.Name}");
}
}
V předchozím kódu se změny konfiguračního souboru JSON po spuštění aplikace nepřečtou. Pokud chcete po spuštění aplikace přečíst změny, použijte IOptionsSnapshot.
Rozhraní možností
- Nepodporuje:
- Čtení konfiguračních dat po spuštění aplikace
- Pojmenované možnosti
- Je registrován jako Singleton a může být vložen do jakékoli životnosti služby.
- Je užitečné ve scénářích, ve kterých by se měly přepočítat možnosti pro každý požadavek. Další informace najdete v tématu Použití IOptionsSnapshot ke čtení aktualizovaných dat.
- Je zaregistrovaný jako Obor, a proto se nedá vložit do služby Singleton.
- Podporuje pojmenované možnosti.
- Slouží k načtení možností a správě oznámení možností pro
TOptions
instance. - Je registrován jako Singleton a může být vložen do jakékoli životnosti služby.
- Podporuje:
- Změna oznámení
- pojmenované možnosti
- Znovu načístelná konfigurace
- Zrušení selektivních možností (IOptionsMonitorCache<TOptions>)
Scénáře po konfiguraci umožňují nastavení nebo změnu možností po dokončení konfigurace IConfigureOptions<TOptions> .
IOptionsFactory<TOptions> zodpovídá za vytváření nových instancí možností. Má jednu Create metodu. Výchozí implementace vezme všechny registrované IConfigureOptions<TOptions> a IPostConfigureOptions<TOptions> nejprve spustí všechny konfigurace, za kterými následuje po konfiguraci. Rozlišuje mezi IConfigureNamedOptions<TOptions> rozhraním a IConfigureOptions<TOptions> volá pouze příslušné rozhraní.
IOptionsMonitorCache<TOptions> používá IOptionsMonitor<TOptions> se k ukládání instancí do mezipaměti TOptions
. Instance IOptionsMonitorCache<TOptions> možností v monitorování zneplatní, aby byla hodnota přepočítána (TryRemove). Hodnoty lze ručně zavést s TryAdd. Metoda Clear se používá, když se všechny pojmenované instance mají znovu vytvořit na vyžádání.
Čtení aktualizovaných dat pomocí IOptionsSnapshot
Pomocí IOptionsSnapshot<TOptions>:
- Možnosti se po dobu životnosti požadavku počítají jednou za požadavek a ukládají se do mezipaměti.
- Může dojít k významnému snížení výkonu, protože se jedná o službu s vymezeným oborem, která se přepočítá na každou žádost. Další informace najdete v tomto problému na GitHubu a vylepšete výkon vazby konfigurace.
- Změny konfigurace se čtou po spuštění aplikace při použití zprostředkovatelů konfigurace, kteří podporují čtení aktualizovaných konfiguračních hodnot.
Rozdíl mezi IOptionsMonitor
a IOptionsSnapshot
je následující:
IOptionsMonitor
je služba Singleton, která načítá aktuální hodnoty možností kdykoli, což je zvlášť užitečné v jednoúčelových závislostech.IOptionsSnapshot
je služba s vymezeným oborem a poskytuje snímek možností v době,IOptionsSnapshot<T>
kdy je objekt vytvořen. Snímky možností jsou navržené pro použití s přechodnými a vymezenými závislostmi.
Následující kód používá IOptionsSnapshot<TOptions>.
public class TestSnapModel : PageModel
{
private readonly MyOptions _snapshotOptions;
public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
{
_snapshotOptions = snapshotOptionsAccessor.Value;
}
public ContentResult OnGet()
{
return Content($"Option1: {_snapshotOptions.Option1} \n" +
$"Option2: {_snapshotOptions.Option2}");
}
}
Následující kód zaregistruje instanci konfigurace, která MyOptions
se sváže s:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
V předchozím kódu se změny konfiguračního souboru JSON po spuštění aplikace načtou.
IOptionsMonitor
Následující kód zaregistruje instanci konfigurace, která MyOptions
je svázaná s.
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
Následující příklad používá IOptionsMonitor<TOptions>:
public class TestMonitorModel : PageModel
{
private readonly IOptionsMonitor<MyOptions> _optionsDelegate;
public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
{
_optionsDelegate = optionsDelegate;
}
public ContentResult OnGet()
{
return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
$"Option2: {_optionsDelegate.CurrentValue.Option2}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
Podpora pojmenovaných možností pomocí IConfigureNamedOptions
Pojmenované možnosti:
- Jsou užitečné, když se několik oddílů konfigurace sváže se stejnými vlastnostmi.
- Rozlišují se malá a velká písmena.
Vezměme například následující soubor appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Místo vytvoření dvou tříd pro vytvoření vazby TopItem:Month
a TopItem:Year
pro každou část se používá následující třída:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
}
Následující kód nakonfiguruje pojmenované možnosti:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
var app = builder.Build();
Následující kód zobrazí pojmenované možnosti:
public class TestNOModel : PageModel
{
private readonly TopItemSettings _monthTopItem;
private readonly TopItemSettings _yearTopItem;
public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
{
_monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
_yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
}
public ContentResult OnGet()
{
return Content($"Month:Name {_monthTopItem.Name} \n" +
$"Month:Model {_monthTopItem.Model} \n\n" +
$"Year:Name {_yearTopItem.Name} \n" +
$"Year:Model {_yearTopItem.Model} \n" );
}
}
Všechny možnosti jsou pojmenované instance. IConfigureOptions<TOptions> instance jsou považovány za cíl instance Options.DefaultName
, což je string.Empty
. IConfigureNamedOptions<TOptions> implementuje IConfigureOptions<TOptions>také . Výchozí implementace má logiku IOptionsFactory<TOptions> , která se má použít odpovídajícím způsobem. Pojmenovaná null
možnost se používá k cílení na všechny pojmenované instance místo na konkrétní pojmenovanou instanci. ConfigureAll a PostConfigureAll používat tuto konvenci.
OptionsBuilder API
OptionsBuilder<TOptions> slouží ke konfiguraci TOptions
instancí. OptionsBuilder
zjednodušuje vytváření pojmenovaných možností, protože se jedná pouze o jediný parametr počátečního AddOptions<TOptions>(string optionsName)
volání místo toho, aby se zobrazoval ve všech následných voláních. Možnosti ověřování a ConfigureOptions
přetížení, která přijímají závislosti služby, jsou k dispozici pouze prostřednictvím OptionsBuilder
.
OptionsBuilder
se používá v části Ověřování možností.
Informace o přidání vlastního úložiště najdete v tématu Použití addOptions ke konfiguraci vlastního úložiště .
Konfigurace možností pomocí služeb DI
Ke službám je možné přistupovat prostřednictvím injektáže závislostí a současně konfigurovat možnosti dvěma způsoby:
Předat delegáta konfigurace zapnuto Configure OptionsBuilder<TOptions>.
OptionsBuilder<TOptions>
poskytuje přetížení Configure , která umožňují použití až pěti služeb ke konfiguraci možností:builder.Services.AddOptions<MyOptions>("optionalName") .Configure<Service1, Service2, Service3, Service4, Service5>( (o, s, s2, s3, s4, s5) => o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Vytvořte typ, který implementuje IConfigureOptions<TOptions> nebo IConfigureNamedOptions<TOptions> zaregistruje typ jako službu.
Doporučujeme předat delegáta Configurekonfigurace , protože vytvoření služby je složitější. Vytvoření typu je ekvivalentní tomu, co architektura dělá při volání Configure. Volání Configure registruje přechodný obecný IConfigureNamedOptions<TOptions>, který má konstruktor, který přijímá obecné typy služby zadané.
Ověřování možností
Ověření možností umožňuje ověření hodnot možností.
Vezměme například následující soubor appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Následující třída se používá k vytvoření vazby k oddílu "MyConfig"
konfigurace a používá několik DataAnnotations
pravidel:
public class MyConfigOptions
{
public const string MyConfig = "MyConfig";
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public string Key1 { get; set; }
[Range(0, 1000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Key2 { get; set; }
public int Key3 { get; set; }
}
Následující kód:
- Volání AddOptions pro získání OptionsBuilder<TOptions> vazby ke
MyConfigOptions
třídě - Volání ValidateDataAnnotations pro povolení ověřování pomocí
DataAnnotations
.
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations();
var app = builder.Build();
Metoda ValidateDataAnnotations
rozšíření je definována v balíčku NuGet Microsoft.Extensions.Options.DataAnnotations . U webových aplikací, které používají Microsoft.NET.Sdk.Web
sadu SDK, se tento balíček implicitně odkazuje ze sdílené architektury.
Následující kód zobrazí konfigurační hodnoty nebo chyby ověření:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptions<MyConfigOptions> _config;
public HomeController(IOptions<MyConfigOptions> config,
ILogger<HomeController> logger)
{
_config = config;
_logger = logger;
try
{
var configValue = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (var failure in ex.Failures)
{
_logger.LogError(failure);
}
}
}
public ContentResult Index()
{
string msg;
try
{
msg = $"Key1: {_config.Value.Key1} \n" +
$"Key2: {_config.Value.Key2} \n" +
$"Key3: {_config.Value.Key3}";
}
catch (OptionsValidationException optValEx)
{
return Content(optValEx.Message);
}
return Content(msg);
}
Následující kód používá složitější ověřovací pravidlo pomocí delegáta:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Key2 != 0)
{
return config.Key3 > config.Key2;
}
return true;
}, "Key3 must be > than Key2."); // Failure message.
var app = builder.Build();
IValidateOptions<TOptions>
a IValidatableObject
Následující třída implementuje IValidateOptions<TOptions>:
public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
public MyConfigOptions _config { get; private set; }
public MyConfigValidation(IConfiguration config)
{
_config = config.GetSection(MyConfigOptions.MyConfig)
.Get<MyConfigOptions>();
}
public ValidateOptionsResult Validate(string name, MyConfigOptions options)
{
string? vor = null;
var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
var match = rx.Match(options.Key1!);
if (string.IsNullOrEmpty(match.Value))
{
vor = $"{options.Key1} doesn't match RegEx \n";
}
if ( options.Key2 < 0 || options.Key2 > 1000)
{
vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
}
if (_config.Key2 != default)
{
if(_config.Key3 <= _config.Key2)
{
vor += "Key3 must be > than Key2.";
}
}
if (vor != null)
{
return ValidateOptionsResult.Fail(vor);
}
return ValidateOptionsResult.Success;
}
}
IValidateOptions
umožňuje přesunout ověřovací kód mimo Program.cs
třídu a do třídy.
Pomocí předchozího kódu je ověřování povoleno Program.cs
pomocí následujícího kódu:
using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
MyConfigOptions.MyConfig));
builder.Services.AddSingleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>();
var app = builder.Build();
Ověřování možností také podporuje IValidatableObject. Ověření třídy v rámci samotné třídy:
- Implementujte
IValidatableObject
rozhraní a jeho Validate metodu v rámci třídy. - Zavolat ValidateDataAnnotations .
Program.cs
ValidateOnStart
Při prvním vytvoření objektu IOptions<TOptions>, IOptionsSnapshot<TOptions>nebo IOptionsMonitor<TOptions> implementace se spustí ověření možností. Pokud chcete spouštět možnosti ověřování dychtivě, zavolejte ValidateOnStart Program.cs
při spuštění aplikace:
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
Možnosti po konfiguraci
Nastavte po konfiguraci pomocí parametru IPostConfigureOptions<TOptions>. Po dokončení konfigurace se spustí po dokončení konfigurace IConfigureOptions<TOptions> :
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
PostConfigure je k dispozici pro pokonfigurované pojmenované možnosti:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
myOptions.Name = "post_configured_name_value";
myOptions.Model = "post_configured_model_value";
});
var app = builder.Build();
Slouží PostConfigureAll k následné konfiguraci všech instancí konfigurace:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
Možnosti aplikace Access v aplikaci Program.cs
Pokud chcete získat přístup nebo IOptions<TOptions> IOptionsMonitor<TOptions> v Program.cs
aplikaci, zavolejteGetRequiredService:WebApplication.Services
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
Další materiály
Vzor možností používá třídy k zajištění přístupu silného typu ke skupinám souvisejících nastavení. Pokud jsou nastavení konfigurace izolované podle scénáře do samostatných tříd, aplikace dodržuje dva důležité principy softwarového inženýrství:
- Zapouzdření:
- Třídy, které závisí na nastavení konfigurace, závisí pouze na nastavení konfigurace, která používají.
- Oddělení obav:
- Nastavení pro různé části aplikace nejsou závislá ani vzájemně svázaná.
Možnosti také poskytují mechanismus pro ověření konfiguračních dat. Další informace najdete v části Možnosti ověření .
Toto téma obsahuje informace o vzoru možností v ASP.NET Core. Informace o použití vzoru možností v konzolových aplikacích najdete v tématu Možnosti v .NET.
Zobrazení nebo stažení ukázkového kódu (postup stažení)
Vytvoření vazby hierarchické konfigurace
Upřednostňovaným způsobem čtení souvisejících hodnot konfigurace je použití vzoru možností. Pokud chcete například přečíst následující konfigurační hodnoty:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Vytvořte následující třídu PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; }
public string Name { get; set; }
}
Třída možností:
- Musí být neabstraktní s veřejným konstruktorem bez parametrů.
- Všechny veřejné vlastnosti pro čtení i zápis typu jsou vázané.
- Pole nejsou vázaná. V předchozím kódu není pole
Position
vázáno. VlastnostPosition
se používá, aby řetězec"Position"
nemusel být v aplikaci pevně zakódován při vytváření vazby třídy na zprostředkovatele konfigurace.
Následující kód:
- Zavolá metodu ConfigurationBinder.Bind pro svázání třídy
PositionOptions
s oddílemPosition
. - Zobrazí konfigurační data pole
Position
.
public class Test22Model : PageModel
{
private readonly IConfiguration Configuration;
public Test22Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
ConfigurationBinder.Get<T>
naváže a vrátí určený typ. ConfigurationBinder.Get<T>
může být pohodlnější než použití ConfigurationBinder.Bind
. Následující kód ukazuje, jak používat ConfigurationBinder.Get<T>
s třídou PositionOptions
:
public class Test21Model : PageModel
{
private readonly IConfiguration Configuration;
public PositionOptions positionOptions { get; private set; }
public Test21Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
positionOptions = Configuration.GetSection(PositionOptions.Position)
.Get<PositionOptions>();
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
Alternativním přístupem při používání vzoru možností je vytvoření vazby oddílu Position
a jeho přidání do kontejneru služby vkládání závislostí. V následujícím kódu se PositionOptions
přidá do kontejneru služby s příkazem Configure a sváže se s konfigurací:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(Configuration.GetSection(
PositionOptions.Position));
services.AddRazorPages();
}
Pomocí předchozího kódu přečte následující kód možnosti pozice:
public class Test2Model : PageModel
{
private readonly PositionOptions _options;
public Test2Model(IOptions<PositionOptions> options)
{
_options = options.Value;
}
public ContentResult OnGet()
{
return Content($"Title: {_options.Title} \n" +
$"Name: {_options.Name}");
}
}
V předchozím kódu se změny konfiguračního souboru JSON po spuštění aplikace nepřečtou. Pokud chcete po spuštění aplikace přečíst změny, použijte IOptionsSnapshot.
Rozhraní možností
- Nepodporuje:
- Čtení konfiguračních dat po spuštění aplikace
- Pojmenované možnosti
- Je registrován jako Singleton a může být vložen do jakékoli životnosti služby.
- Je užitečné ve scénářích, ve kterých by se měly přepočítat možnosti pro každý požadavek. Další informace najdete v tématu Použití IOptionsSnapshot ke čtení aktualizovaných dat.
- Je registrován jako Obor, a proto nelze vložit do služby Singleton.
- Podporuje pojmenované možnosti.
- Slouží k načtení možností a správě oznámení možností pro
TOptions
instance. - Je registrován jako Singleton a může být vložen do jakékoli životnosti služby.
- Podporuje:
- Změna oznámení
- Pojmenované možnosti
- Znovu načístelná konfigurace
- Zrušení selektivních možností (IOptionsMonitorCache<TOptions>)
Scénáře po konfiguraci umožňují nastavení nebo změnu možností po dokončení konfigurace IConfigureOptions<TOptions> .
IOptionsFactory<TOptions> zodpovídá za vytváření nových instancí možností. Má jednu Create metodu. Výchozí implementace vezme všechny registrované IConfigureOptions<TOptions> a IPostConfigureOptions<TOptions> nejprve spustí všechny konfigurace, za kterými následuje po konfiguraci. Rozlišuje mezi IConfigureNamedOptions<TOptions> rozhraním a IConfigureOptions<TOptions> volá pouze příslušné rozhraní.
IOptionsMonitorCache<TOptions> používá IOptionsMonitor<TOptions> se k ukládání instancí do mezipaměti TOptions
. Instance IOptionsMonitorCache<TOptions> možností v monitorování zneplatní, aby byla hodnota přepočítána (TryRemove). Hodnoty lze ručně zavést s TryAdd. Metoda Clear se používá, když se všechny pojmenované instance mají znovu vytvořit na vyžádání.
Čtení aktualizovaných dat pomocí IOptionsSnapshot
Použití IOptionsSnapshot<TOptions>, možnosti se počítají jednou za požadavek při přístupu a ukládání do mezipaměti po dobu životnosti požadavku. Změny konfigurace se čtou po spuštění aplikace při použití zprostředkovatelů konfigurace, kteří podporují čtení aktualizovaných konfiguračních hodnot.
Rozdíl mezi IOptionsMonitor
a IOptionsSnapshot
je následující:
IOptionsMonitor
je služba Singleton, která načítá aktuální hodnoty možností kdykoli, což je zvlášť užitečné v jednoúčelových závislostech.IOptionsSnapshot
je služba s vymezeným oborem a poskytuje snímek možností v době,IOptionsSnapshot<T>
kdy je objekt vytvořen. Snímky možností jsou navržené pro použití s přechodnými a vymezenými závislostmi.
Následující kód používá IOptionsSnapshot<TOptions>.
public class TestSnapModel : PageModel
{
private readonly MyOptions _snapshotOptions;
public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
{
_snapshotOptions = snapshotOptionsAccessor.Value;
}
public ContentResult OnGet()
{
return Content($"Option1: {_snapshotOptions.Option1} \n" +
$"Option2: {_snapshotOptions.Option2}");
}
}
Následující kód zaregistruje instanci konfigurace, která MyOptions
se sváže s:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
}
V předchozím kódu se změny konfiguračního souboru JSON po spuštění aplikace načtou.
IOptionsMonitor
Následující kód zaregistruje instanci konfigurace, která MyOptions
je svázaná s.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
}
Následující příklad používá IOptionsMonitor<TOptions>:
public class TestMonitorModel : PageModel
{
private readonly IOptionsMonitor<MyOptions> _optionsDelegate;
public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
{
_optionsDelegate = optionsDelegate;
}
public ContentResult OnGet()
{
return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
$"Option2: {_optionsDelegate.CurrentValue.Option2}");
}
}
V předchozím kódu se ve výchozím nastavení změní konfigurační soubor JSON po spuštění aplikace.
Podpora pojmenovaných možností pomocí IConfigureNamedOptions
Pojmenované možnosti:
- Jsou užitečné, když se několik oddílů konfigurace sváže se stejnými vlastnostmi.
- Rozlišují se malá a velká písmena.
Vezměme například následující soubor appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Místo vytvoření dvou tříd pro vytvoření vazby TopItem:Month
a TopItem:Year
pro každou část se používá následující třída:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; }
public string Model { get; set; }
}
Následující kód nakonfiguruje pojmenované možnosti:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<TopItemSettings>(TopItemSettings.Month,
Configuration.GetSection("TopItem:Month"));
services.Configure<TopItemSettings>(TopItemSettings.Year,
Configuration.GetSection("TopItem:Year"));
services.AddRazorPages();
}
Následující kód zobrazí pojmenované možnosti:
public class TestNOModel : PageModel
{
private readonly TopItemSettings _monthTopItem;
private readonly TopItemSettings _yearTopItem;
public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
{
_monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
_yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
}
public ContentResult OnGet()
{
return Content($"Month:Name {_monthTopItem.Name} \n" +
$"Month:Model {_monthTopItem.Model} \n\n" +
$"Year:Name {_yearTopItem.Name} \n" +
$"Year:Model {_yearTopItem.Model} \n" );
}
}
Všechny možnosti jsou pojmenované instance. IConfigureOptions<TOptions> instance jsou považovány za cíl instance Options.DefaultName
, což je string.Empty
. IConfigureNamedOptions<TOptions> implementuje IConfigureOptions<TOptions>také . Výchozí implementace má logiku IOptionsFactory<TOptions> , která se má použít odpovídajícím způsobem. Pojmenovaná null
možnost se používá k cílení na všechny pojmenované instance místo na konkrétní pojmenovanou instanci. ConfigureAll a PostConfigureAll používat tuto konvenci.
OptionsBuilder API
OptionsBuilder<TOptions> slouží ke konfiguraci TOptions
instancí. OptionsBuilder
zjednodušuje vytváření pojmenovaných možností, protože se jedná pouze o jediný parametr počátečního AddOptions<TOptions>(string optionsName)
volání místo toho, aby se zobrazoval ve všech následných voláních. Možnosti ověřování a ConfigureOptions
přetížení, která přijímají závislosti služby, jsou k dispozici pouze prostřednictvím OptionsBuilder
.
OptionsBuilder
se používá v části Ověřování možností.
Informace o přidání vlastního úložiště najdete v tématu Použití addOptions ke konfiguraci vlastního úložiště .
Konfigurace možností pomocí služeb DI
Ke službám je možné přistupovat prostřednictvím injektáže závislostí a současně konfigurovat možnosti dvěma způsoby:
Předat delegáta konfigurace zapnuto Configure OptionsBuilder<TOptions>.
OptionsBuilder<TOptions>
poskytuje přetížení Configure , která umožňují použití až pěti služeb ke konfiguraci možností:services.AddOptions<MyOptions>("optionalName") .Configure<Service1, Service2, Service3, Service4, Service5>( (o, s, s2, s3, s4, s5) => o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Vytvořte typ, který implementuje IConfigureOptions<TOptions> nebo IConfigureNamedOptions<TOptions> zaregistruje typ jako službu.
Doporučujeme předat delegáta Configurekonfigurace , protože vytvoření služby je složitější. Vytvoření typu je ekvivalentní tomu, co architektura dělá při volání Configure. Volání Configure registruje přechodný obecný IConfigureNamedOptions<TOptions>, který má konstruktor, který přijímá obecné typy služby zadané.
Ověřování možností
Ověření možností umožňuje ověření hodnot možností.
Vezměme například následující soubor appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Následující třída vytvoří vazbu na "MyConfig"
oddíl konfigurace a použije několik DataAnnotations
pravidel:
public class MyConfigOptions
{
public const string MyConfig = "MyConfig";
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public string Key1 { get; set; }
[Range(0, 1000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Key2 { get; set; }
public int Key3 { get; set; }
}
Následující kód:
- Volání AddOptions pro získání OptionsBuilder<TOptions> vazby ke
MyConfigOptions
třídě - Volání ValidateDataAnnotations pro povolení ověřování pomocí
DataAnnotations
.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions<MyConfigOptions>()
.Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations();
services.AddControllersWithViews();
}
Metoda ValidateDataAnnotations
rozšíření je definována v balíčku NuGet Microsoft.Extensions.Options.DataAnnotations . U webových aplikací, které používají Microsoft.NET.Sdk.Web
sadu SDK, se tento balíček implicitně odkazuje ze sdílené architektury.
Následující kód zobrazí konfigurační hodnoty nebo chyby ověření:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptions<MyConfigOptions> _config;
public HomeController(IOptions<MyConfigOptions> config,
ILogger<HomeController> logger)
{
_config = config;
_logger = logger;
try
{
var configValue = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (var failure in ex.Failures)
{
_logger.LogError(failure);
}
}
}
public ContentResult Index()
{
string msg;
try
{
msg = $"Key1: {_config.Value.Key1} \n" +
$"Key2: {_config.Value.Key2} \n" +
$"Key3: {_config.Value.Key3}";
}
catch (OptionsValidationException optValEx)
{
return Content(optValEx.Message);
}
return Content(msg);
}
Následující kód používá složitější ověřovací pravidlo pomocí delegáta:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions<MyConfigOptions>()
.Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Key2 != 0)
{
return config.Key3 > config.Key2;
}
return true;
}, "Key3 must be > than Key2."); // Failure message.
services.AddControllersWithViews();
}
IValidateOptions pro komplexní ověřování
Následující třída implementuje IValidateOptions<TOptions>:
public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
public MyConfigOptions _config { get; private set; }
public MyConfigValidation(IConfiguration config)
{
_config = config.GetSection(MyConfigOptions.MyConfig)
.Get<MyConfigOptions>();
}
public ValidateOptionsResult Validate(string name, MyConfigOptions options)
{
string vor=null;
var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
var match = rx.Match(options.Key1);
if (string.IsNullOrEmpty(match.Value))
{
vor = $"{options.Key1} doesn't match RegEx \n";
}
if ( options.Key2 < 0 || options.Key2 > 1000)
{
vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
}
if (_config.Key2 != default)
{
if(_config.Key3 <= _config.Key2)
{
vor += "Key3 must be > than Key2.";
}
}
if (vor != null)
{
return ValidateOptionsResult.Fail(vor);
}
return ValidateOptionsResult.Success;
}
}
IValidateOptions
umožňuje přesunout ověřovací kód mimo StartUp
třídu a do třídy.
Pomocí předchozího kódu je ověřování povoleno Startup.ConfigureServices
pomocí následujícího kódu:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyConfigOptions>(Configuration.GetSection(
MyConfigOptions.MyConfig));
services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>());
services.AddControllersWithViews();
}
Možnosti po konfiguraci
Nastavte po konfiguraci pomocí parametru IPostConfigureOptions<TOptions>. Po dokončení konfigurace se spustí po dokončení konfigurace IConfigureOptions<TOptions> :
services.PostConfigure<MyOptions>(myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
PostConfigure je k dispozici pro pokonfigurované pojmenované možnosti:
services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
Slouží PostConfigureAll k následné konfiguraci všech instancí konfigurace:
services.PostConfigureAll<MyOptions>(myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
Přístup k možnostem při spuštění
IOptions<TOptions> a IOptionsMonitor<TOptions> lze je použít v Startup.Configure
, protože služby jsou vytvořeny před spuštěním Configure
metody.
public void Configure(IApplicationBuilder app,
IOptionsMonitor<MyOptions> optionsAccessor)
{
var option1 = optionsAccessor.CurrentValue.Option1;
}
Nepoužívejte IOptions<TOptions> ani IOptionsMonitor<TOptions> v Startup.ConfigureServices
. Kvůli objednávání registrací služeb může existovat nekonzistentní stav možností.
Options.ConfigurationExtensions – balíček NuGet
Na balíček Microsoft.Extensions.Options.ConfigurationExtensions se implicitně odkazuje v aplikacích ASP.NET Core.